FHEM Forum

FHEM => Automatisierung => DOIF => Thema gestartet von: mumpitzstuff am 12 Juni 2020, 21:47:48

Titel: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 12 Juni 2020, 21:47:48
Ich habe mich mal hingesetzt und ein DOIF generiert, das die aktuellen Fernsehdaten einer Woche als xml von einem Server lädt (das DOIF macht das 1x alle 3-4 Tage) und daraus eine Programmzeitschrift generiert. Sowohl der Download als auch die Generierung geschehen non blocking. Es werden 2 Dinge generiert. Zum Einen die nächsten 3 Sendungen ab jetzt und zum Anderen die 3 Sendungen ab 20:15 Uhr. Die einzelnen Sendungen sind anklickbar und zeigen dann eine detaillierte Beschreibung zu der Sendung.

Nachdem das DOIF erstellt wurde, dauert es 5min bis die aktuellen Sendungen sichtbar werden. Die Prime Sendungen sind nach weiteren 5 Minuten sichtbar. Wenn die Prime Sendungen zwischen 20:15 Uhr und 0:00 aktualisiert werden, dann laufen sie quasi mit, da keine veralteten Sendungen angezeigt werden. Erst nach 0:30 werden dann die wirklichen Prime Sendungen des nächsten Tages (20:15 Uhr Sendungen) angezeigt.

Es gibt genau eine Vorbedingung, damit das DOIF funktioniert (alle Dinge ab 2. sind optional).

1.) XML::Bare muss mind. in der Version 0.53 installiert sein. Das kann man z.B. hiermit erledigen:

sudo apt-get install libxml-bare-perl
2.) Will man sich die Senderlogos anzeigen lassen, dann muss das Verzeichnis "/opt/fhem/www/images/default/tv" erstellt und die Rechte so gesetzt sein, das FHEM darauf zugreifen kann. Danach muss man die Senderlogos als PNGs in dieses Verzeichnis kopieren und ebenfalls die entsprechenden Rechte setzen. Die Dateien müssen die richtigen Namen besitzen! Diese kann man in der ersten Spalte der Darstellung sehen. Steht hier zum Beispiel "tv/ard" dann muss die Datei "/opt/fhem/www/images/default/tv/ard.png" heissen. Eine Quelle dafür ist z.B. (meine Logos kann ich leider aus rechtlichen Gründen hier nicht zur Verfügung stellen, aber höflich per PM fragen funktioniert vielleicht...):

https://github.com/3PO/Senderlogos/archive/master.zip (https://github.com/3PO/Senderlogos/archive/master.zip)

https://github.com/picons/picons/archive/master.zip (https://github.com/picons/picons/archive/master.zip)

https://de.wikipedia.org/wiki/Liste_deutschsprachiger_Fernsehsender (https://de.wikipedia.org/wiki/Liste_deutschsprachiger_Fernsehsender)

https://iptv-org.github.io (https://iptv-org.github.io/)

SVG Logos gibt es z.B. hier (habe ich noch nie verwendet, sollte aber auch gehen):

https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de (https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de)

Ansonsten gibt es diverse Programmezeitschriften online, bei denen man sich die Bilder der Sender runterladen kann.

3.) Wenn man Sender hinzufügen möchte, dann kann man sich die original xml Dateien runterladen und die entsprechenden Sender raus suchen.

http://rytecepg.dyndns.tv/epg_data/ (http://rytecepg.dyndns.tv/epg_data/)

Danach muss man folgende Dinge anpassen (wenn man einen Sender entfernen möchte, muss man die entsprechenden Dinge ebenfalls anpassen):
a) Die Variable $_channelFilter.
b) Im Attribut uiTable muss man 2 Zeilen hinzufügen: "TPL_TV($SELF,next,<sender name>,<logo name>)" und weiter unten "TPL_TV($SELF,prime,<sender name>,<logo name>)"
c) Danach muss man noch die Formatierung ebenfalls im Attribut uiTable anpassen. Diese beginnen mit $TR und $TD.

Die xml Daten stellen jede Menge weiterer Sender zur Verfügung.

Unten habe ich auch mal ein Testscript dl.pl angehangen, womit man seinen channelfilter erst einmal überprüfen kann. Einfach den channelfilter im Script anpassen und ausführen und man sieht das Ergebnis erst einmal in einer Testdatei und kann, wenn alles funktioniert, das Regex ins DOIF übertragen. Es ist wichtig, das man immer den Text aus der id nimmt!

<channel id="ARD.de">
4.) Es stehen 2 Templates zur Verfügung. TPL_TV wird normalerweise verwendet und stellt das Programmlogo und 3 Sendezeiten dar. Darüber hinaus kann auch TPL_TVSET verwendet werden. Hier kann durch ein Klick auf das Programmlogo ein set Befehl an ein beliebiges FHEM Device geschickt werden, um z.B. den Fernsehsender aus FHEM heraus zu wechseln.

Beispiel:
TPL_TV($SELF,next,ARD,ard)kann ersetzt werden durch:
TPL_TVSET($SELF,next,ARD,ard,irblasterdevice,send IR_SAT_DasErste)
5.) Wenn man andere Sender oder mehr als die vorhandenen haben möchte, kann man z.B. hier sehen was es sonst noch alles gibt:

http://rytecepg.dyndns.tv/epg_data/ (http://rytecepg.dyndns.tv/epg_data/)

Im DOIF werden nur die beiden Dateien rytecDE_Basic.xz und rytecDE_Common.xz geladen und gemerged. Das bdedeutet, das man aktuell nur Sender aus diesen beiden Dateien anzeigen lassen kann. Es gibt aber die Möglichkeit weitere Dateien zu mergen und dann ebenfalls anzeigen zu lassen wie z.B. rytecDE_SportMovies.xz.

Dazu muss man einfach die Funktion "sub tvDownloadMerge()" suchen und diese ersetzen:

  sub tvDownloadMerge()
  {
    my $output = '';

    ## other server
    ## http://www.xmltvepg.nl
    ## http://rytecepg.epgspot.com/epg_data
    ## http://epg.vuplus-community.net
    ## http://rytecepg.wanwizard.eu
    ## http://rytecepg.dyndns.tv/epg_data
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz
    ## alternative: https://iptv-org.github.io/epg/guides/de.xml (must be downloaded every day!)
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);
    ##$output .= qx(wget $_server/rytecDE_SportMovies.xz -O $_path/rytecDE_SportMovies.xz 2>&1 || rm -f $_path/rytecDE_SportMovies.xz 2>&1);
    ##$output .= qx(xz -df $_path/rytecDE_SportMovies.xz 2>&1);
    ## dont forget to change the following line from "if ([00:00:30|Mo Do])" to "if ([00:00:30])"
    ##$output .= qx(wget https://iptv-org.github.io/epg/guides/de.xml.gz -O $_path/rytecDE_Custom.gz 2>&1 || rm -f $_path/rytecDE_Custom.gz 2>&1);
    ##$output .= qx(gzip -d $_path/rytecDE_Custom.gz 2>&1);
   
    ## download and merge other files here if needed

    tvMerge($_dataFile, $_path.'/rytecDE_Common');
    ##tvMerge($_dataFile, $_path.'/rytecDE_Common', $_path.'/rytecDE_SportMovies');
    ##tvMerge($_path.'/rytecDE_Custom');

    return $output;
  }

durch

  sub tvDownloadMerge()
  {
    my $output = '';

    ## other server
    ## http://www.xmltvepg.nl
    ## http://rytecepg.epgspot.com/epg_data
    ## http://epg.vuplus-community.net
    ## http://rytecepg.wanwizard.eu
    ## http://rytecepg.dyndns.tv/epg_data
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz
    ## alternative: https://iptv-org.github.io/epg/guides/de.xml (must be downloaded every day!)
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);
    $output .= qx(wget $_server/rytecDE_SportMovies.xz -O $_path/rytecDE_SportMovies.xz 2>&1 || rm -f $_path/rytecDE_SportMovies.xz 2>&1);
    $output .= qx(xz -df $_path/rytecDE_SportMovies.xz 2>&1);
    ## dont forget to change the following line from "if ([00:00:30|Mo Do])" to "if ([00:00:30])"
    ##$output .= qx(wget https://iptv-org.github.io/epg/guides/de.xml.gz -O $_path/rytecDE_Custom.gz 2>&1 || rm -f $_path/rytecDE_Custom.gz 2>&1);
    ##$output .= qx(gzip -d $_path/rytecDE_Custom.gz 2>&1);
   
    ## download and merge other files here if needed

    ##tvMerge($_dataFile, $_path.'/rytecDE_Common');
    tvMerge($_dataFile, $_path.'/rytecDE_Common', $_path.'/rytecDE_SportMovies');
    ##tvMerge($_path.'/rytecDE_Custom');

    return $output;
  }

ersetzen. Das Spiel lässt sich beliebig fortsetzen.

Im Folgenden ist meine Version zu sehen, allerdings hat ein anderer User ebenfalls eine modifizierte Version zur Verfügung gestellt. Diese könnt ihr hier finden: https://forum.fhem.de/index.php/topic,112081.msg1255378.html#msg1255378 (https://forum.fhem.de/index.php/topic,112081.msg1255378.html#msg1255378)

defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  ## sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:DasErste\.|ZDF\.|ZDFinfo\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeo(?:HD|Wild)\.|GeoTV\.|CuriosityChannel\.|Sky1\.|WELT\.|phoenix\.|ServusHD\.|BILD\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.|CrimeInvestigation\.|ComedyCentralVIVA\.|Universal\.|DiscoveryHD\.|eSports1\.)/;;\
  ## telnet port must not be password protected (open)\
  ## this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  ## can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  ## path to fhem installation\
  $_path = '/opt/fhem';;\
  ## path to datafile to be parsed to get the tv data\
  $_dataFile = $_path.'/rytecDE_Basic';;\
  ## download server to be used\
  $_server = AttrVal("$SELF", "server", "http://www.xmltvepg.nl");;\
  ## enable/disable unused channel filtering on filemerge (enabled = small file and less readings = faster)\
  $_filterChannels = 1;;\
  ## enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  ## keep tv data in RAM (faster but needs more RAM and the initial load data call is BLOCKING / disable it if you are low on RAM)\
  $_keepDataInRam = 0;;\
  ## enable/disable use of Time::Piece (timepiece is faster but not installed on some systems (sudo cpanm Time::Piece))\
  $_timepiece = 0;;\
\
  ## internal variables\
  $_startTimes = ();;\
  $_tvData = ();;\
  $_isDataLoaded = 0;;\
\
\
  sub filterText($)\
  {\
    $_[0] =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    $_[0] =~ s/[\n]/<br>/g;;\
\
    return $_[0];;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
\
      ## fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      ## slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
\
    foreach my $d (sort keys %::defs) \
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }\
\
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
\
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
\
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
\
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $tvDataRef;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    my $old = time() + $_timeAdjust;;\
\
    ## check if any update is needed\
    if ((0 != $_updateBasedOnStarttimes) && ('prime' ne $mode) && keys(%{$_startTimes}))\
    {\
      my $nothingTodo = 1;;\
      foreach (keys(%{$_startTimes}))\
      {\
        if ($_startTimes{$_} <= $old)\
        {\
          $nothingTodo = 0;;\
          ::Log3 $device, 4, $device.': Update is not blocked because at least one actual program is finished (reading: '.$_.', start: '.$_startTimes{$_}.', old: '.$old.').';;\
          last;;\
        }\
      }\
      \
      if (0 != $nothingTodo)\
      {\
        ::Log3 $device, 4, $device.': Update is blocked because no actual program was finished.';;\
        return %{$_startTimes};;\
      }\
    }\
    \
    if ((0 == $_keepDataInRam) || (0 == $_isDataLoaded))\
    {\
        $obj = XML::Bare->new(file => $_dataFile);;\
        $xml = $obj->parse() if (!$@);;\
        $tvDataRef = \@{forcearray($xml->{'tv'}{'programme'})} if (!$@);;\
    }\
    else\
    {\
        $tvDataRef = \@{$_tvData};;\
    }\
\
    if (!$@)\
    {\
      ## preallocate memory\
      vec($sendTelnet, 10000, 8) = 0;;\
      $sendTelnet = '';;\
      \
      foreach (@{$tvDataRef})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
        \
        ## filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
\
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (reading: '.$reading.', start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
\
          if (($i < 3) && ('next' eq $mode))\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            \
            my $starttime = substr(FmtDateTime($start), 0, 19);;\
            my $oldstarttime = get_Reading('next_'.$reading.'_'.$fi.'_btime');;\
            \
            ## prevent any update which is not required\
            if ($starttime ne $oldstarttime)\
            {\
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' next_'.$reading.'_'.$fi.'_btime ';;\
              $sendTelnet .= $starttime;;\
\
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' next_'.$reading.'_'.$fi.'_title ';;\
              $sendTelnet .= filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
\
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' next_'.$reading.'_'.$fi.'_desc ';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $sendTelnet .= filterText($_->{'sub-title'}{'value'}).'\n\n';;\
              }\
              else\
              {\
                $sendTelnet .= 'na\n\n';;\
              }\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $sendTelnet .= filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $sendTelnet .= 'na';;\
              }\
\
              $k++;;\
            }\
            \
            $i++;;\
          }\
\
          if (($n < 3) && ('prime' eq $mode))\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
\
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
\
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' prime_'.$reading.'_'.$fn.'_btime ';;\
              $sendTelnet .= substr(FmtDateTime($start), 0, 19);;\
                            \
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' prime_'.$reading.'_'.$fn.'_title ';;\
              $sendTelnet .= filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              \
              $sendTelnet .= ";;setreading $device";;\
              $sendTelnet .= ' prime_'.$reading.'_'.$fn.'_desc ';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $sendTelnet .= filterText($_->{'sub-title'}{'value'}).'\n\n';;\
              }\
              else\
              {\
                $sendTelnet .= 'na\n\n';;\
              }\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $sendTelnet .= filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $sendTelnet .= 'na';;\
              }\
                            \
              $k++;;\
              $n++;;\
            }\
          }\
\
          if ($k >= 10)\
          {\
            ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
\
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
\
    return %{$_startTimes};;\
  }\
\
  sub tvMerge\
  {\
    my ($dstName, @srcNames) = @_;;\
    my $fh;;\
    my $data;;\
    my $start = '';;\
    my $channels = '';;\
    my $channels_flt = '';;\
    my $programms = '';;\
    my $programms_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    if (-e $dstName)\
    {\
      open($fh, '<', $dstName) or die "Can't open file $!";;\
      read($fh, $data, -s $fh);;\
      close($fh);;\
\
      if (-1 != ($pos = index($data, '<channel ')))\
      {\
        $start = substr($data, 0, $pos);;\
      }\
\
      if (-1 != ($pos = rindex($data, '</programme>')))\
      {\
        $end = substr($data, $pos + 12);;\
      }\
\
      for (my $i = 0;; $i < (scalar(@srcNames) + 1);; $i++)\
      {\
        if (0 != $i)\
        {\
          my $file = $srcNames[$i - 1];;\
\
          if (-e $file)\
          {\
            open($fh, '<', $file) or die "Can't open file $!";;\
            read($fh, $data, -s $fh);;\
            close($fh);;\
          }\
          else\
          {\
            last;;\
          }\
        }\
\
        while ($data =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
        {\
          if (0 != $_filterChannels)\
          {\
            $_ = $1;;\
\
            if ($2 =~ $_channelFilter)\
            {\
              $channels_flt .= $_;;\
            }\
          }\
          else\
          {\
            $channels .= $1;;\
          }\
        }\
\
        while ($data =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
        {\
          if (0 != $_filterChannels)\
          {\
            $_ = $1;;\
\
            if ($2 =~ $_channelFilter)\
            {\
              $programms_flt .= $_;;\
            }\
          }\
          else\
          {\
            $programms .= $1;;\
          }\
        }\
      }\
\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (0 != $_filterChannels)\
      {\
        print $fh $start.$channels_flt.$programms_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels.$programms.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';;\
\
    ## other server see below\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
\
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl\
    ## http://rytecepg.epgspot.com/epg_data\
    ## http://epg.vuplus-community.net\
    ## http://rytecepg.wanwizard.eu\
    ## http://rytecepg.dyndns.tv/epg_data\
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz\
    ## alternative: https://iptv-org.github.io/epg/guides/de.xml (must be downloaded every day!)\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
    ##$output .= qx(wget $_server/rytecDE_SportMovies.xz -O $_path/rytecDE_SportMovies.xz 2>&1 || rm -f $_path/rytecDE_SportMovies.xz 2>&1);;\
    ##$output .= qx(xz -df $_path/rytecDE_SportMovies.xz 2>&1);;\
    ## dont forget to change the following line from "if ([00:00:30|Mo Do])" to "if ([00:00:30])"\
    ##$output .= qx(wget https://iptv-org.github.io/epg/guides/de.xml.gz -O $_path/rytecDE_Custom.gz 2>&1 || rm -f $_path/rytecDE_Custom.gz 2>&1);;\
    ##$output .= qx(gzip -d $_path/rytecDE_Custom.gz 2>&1);;\
    \
    ## download and merge other files here if needed\
\
    tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
    ##tvMerge($_dataFile, $_path.'/rytecDE_Common', $_path.'/rytecDE_SportMovies');;\
    ##tvMerge($_path.'/rytecDE_Custom');;\
\
    return $output;;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
\
    ## prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
\
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
\
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
\
    $output = tvDownloadMerge();;\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    ## be aware that this call is BLOCKING!\
    if (0 != $_keepDataInRam)\
    {\
        my $obj = XML::Bare->new(file => $_dataFile);;\
        my $xml = $obj->parse() if (!$@);;\
        $_tvData = @{forcearray($xml->{'tv'}{'programme'})} if (!$@);;\
        if (!$@)\
        {\
          $_isDataLoaded = 1;;\
        }\
        else\
        {\
          $_isDataLoaded = 0;;\
        }\
    }\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
\
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
\
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
\
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @newStartTimes) = split("\\|", shift);;\
\
    for (my $i = 0;; $i < scalar(@newStartTimes);; $i += 2)\
    {\
      $_startTimes{$newStartTimes[$i]} = $newStartTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_PARSE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 180, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 420, 'startParse("$SELF", "prime")');;\
}\
{[00:00:30|Mo Do];;startDownload("$SELF")}\
## start in a raster of 5min\
{[+:05];;startParse("$SELF", 'next')}\
## start between next updates\
{[00:32:30];;startParse("$SELF", 'prime')}\

attr doif_TEST userattr server:http://www.xmltvepg.nl,http://epg.vuplus-community.net,http://rytecepg.epgspot.com/epg_data,http://rytecepg.wanwizard.eu,http://rytecepg.dyndns.tv/epg_data
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST event-on-change-reading .*
attr doif_TEST room TV
attr doif_TEST server http://www.xmltvepg.nl
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
    \
  ## 39 normal channels, 2 heading lines and 38 prime channels\
  ## 41 = 39 (normal channels) + 2 (headings)\
  ## 79 = 39 (normal channels) + 2 (headings) + 38 (prime channels)\
  ## 40 = 39 (normal channels) + 1 (first heading)\
  $TR{0,41} = "style='color:yellow;;;;text-align:center;;;;font-weight:bold;;;;font-size:18px'";;\
  $TD{0..39,41..79}{2,4} = "style='font-size:16px;;;;border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..39,41..79}{0} = "align='center' style='border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..79}{1,3,5,6} = "style='font-size:16px;;;;'";;\
  $TD{40}{0..6} = "style='border-top-style:solid;;;;border-bottom-style:solid;;;;border-color:#CCCCCC;;;;border-top-width:1px;;;;border-bottom-width:1px;;;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub showIconIP\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF", "$device", "") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub unfold\
  {\
    ##my ($title, $desc) = @_;;\
\
    ##$title = 'na' if (!defined($title));;\
    ##$desc = 'na'."\n\n".'na' if (!defined($desc));;\
    \
    ##$title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    ##$desc =~ s/<br>/\n/g;;\
    ##$desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    ##$desc =~ s/[\r\'\"]/ /g;;\
    ##$desc =~ s/[\n]|\\n/<br>/g;;\
\
    ##return "<a href=\"#!\" onclick=\"FW_okDialog(&#39;;".$desc."&#39;;)\">".$title."</a>";;\
    \
    $_[0] = 'na' if (!defined($_[0]));;\
    $_[1] = 'na'."\n\n".'na' if (!defined($_[1]));;\
    \
    $_[0] =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $_[1] =~ s/<br>/\n/g;;\
    $_[1] =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $_[1] =~ s/[\r\'\"]/ /g;;\
    $_[1] =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(&#39;;".$_[1]."&#39;;)\">".$_[0]."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],11,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],11,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],11,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVSET($SELF,next,DasErste,ard,<ir blaster device>,<ir blaster command>)\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],11,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],11,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],11,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVIP($SELF,next,DasErste,ard,VIEW1,29438503040)\
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],11,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],11,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],11,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,DasErste,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,ProSieben,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,KabelEins,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,Universal,universal)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,next,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,phoenix,phoenix)\
TPL_TV($SELF,next,ZDFinfo,zdfinfo)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,WELT,welt)\
TPL_TV($SELF,next,ServusHD,servus)\
TPL_TV($SELF,next,BILD,bild)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,GeoTV,geotv)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,NatGeoWild,natgeowild)\
TPL_TV($SELF,next,DiscoveryHD,discovery)\
TPL_TV($SELF,next,Sky1,skyone)\
TPL_TV($SELF,next,CuriosityChannel,curiosity)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,eSports1,esports1)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,ProSieben,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,KabelEins,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,Universal,universal)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,prime,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,phoenix,phoenix)\
TPL_TV($SELF,prime,ZDFinfo,zdfinfo)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,WELT,welt)\
TPL_TV($SELF,prime,ServusHD,servus)\
TPL_TV($SELF,prime,BILD,bild)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,GeoTV,geotv)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,NatGeoWild,natgeowild)\
TPL_TV($SELF,prime,DiscoveryHD,discovery)\
TPL_TV($SELF,prime,Sky1,skyone)\
TPL_TV($SELF,prime,CuriosityChannel,curiosity)\
TPL_TV($SELF,prime,TLC,tlc)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 12 Juni 2020, 22:02:49
Ich setze den Post für ne Weile hoch. Es könnte für den einen oder anderen interessant sein. Es ist offenbar etwas mehr als nur DOIF-DOELSEIF-DOELSE, das, was die meisten unter DOIF verstehen ;)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 13 Juni 2020, 16:31:36
Zitat von: Damian am 12 Juni 2020, 22:02:49
Ich setze den Post für ne Weile hoch. Es könnte für den einen oder anderen interessant sein. Es ist offenbar etwas mehr als nur DOIF-DOELSEIF-DOELSE, das, was die meisten unter DOIF verstehen ;)
Diese "Adelung" ist für mich gerechtfertigt - ein toller Showcase für die Mächtigkeit von DOIF.

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 13 Juni 2020, 18:20:56
Warum der Umweg über Telnet ? Wenn ich nichts übersehen habe, machst Du nur "setreading" Kommandos?

EDIT: ah ok verstanden. Du machst verschiedene Sachen in externalisierten Prozesse.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 13 Juni 2020, 21:59:26
Ich habe zuerst versucht die Daten als return zurück zu geben, aber das hat mir das gesamte System abstürzen lassen. Der Weg über Telnet ging dagegen erst einmal problemlos. Ich bin aber noch dran und versuche genau diesen Punkt noch zu optimieren. Vielleicht finde ich noch einen eleganteren Weg.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 14 Juni 2020, 02:05:19
Es ist leider nicht möglich auf den separaten Telnet Port zu verzichten. Wenn das Blocking Modul alle Daten auf einmal per Telnet aus dem Fork in den Hauptprozess pushen will, dann geschehen sehr merkwürdige Dinge aufgrund der Menge an Daten. Genaueres konnte ich leider nicht rausbekommen, aber der Datentransfer im Blocking Modul stürzt entweder komplett ab oder überträgt nur einen Teil der Daten. Das endet irgndwann im Datenchaos. Ich muss daher erst einmal bei dieser Variante bleiben. Ich könnte lediglich versuchen, so wie das Blocking Modul auch, eine temporäre Telnet Verbindung zu erstellen und nach der Übertragung wieder zu löschen. Dann muss sich der Anwender nicht darum kümmern.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 09:39:09
Hi mumpitzstuff. Super Sache. Habe ich so toll noch nicht gesehen. Danke.

Ich habe auch mal probiert.
Bei mir dauerte es lange, bis etwas passierte. Das stört mich aber nicht.

Die Senderlogos sehe ich nicht. Vermutlich, weil Pfad und Dateien nicht existieren.
Verrätst du mir, woher du die geladen hast?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 10:58:52
Ich habe sie mir mal von
https://download.avm.de/tv/ (https://download.avm.de/tv/)
geholt und nach /opt/fhem/www/images/tv kopiert.

Funktioniert aber nicht!

Gruß

Carlos
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 12:25:40
Zitat von: carlos am 14 Juni 2020, 10:58:52
Ich habe sie mir mal von
https://download.avm.de/tv/ (https://download.avm.de/tv/)
geholt und nach /opt/fhem/www/images/tv kopiert.

Funktioniert aber nicht!

Gruß

Carlos

Klar. Wenn Du eine andere Quelle benutzt, musst Du natürlich die Parse Funktion entspr. anpassen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 12:28:45
Die werden aber bei mir und bei invers überhaupt nicht angezeigt, da steht z.b. nur "tv/ard".

Gruß

Carlos
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 12:54:26
Genau so ist es leider. Keine Anzeige.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 13:03:43
Zitat von: Invers am 14 Juni 2020, 12:54:26
Genau so ist es leider. Keine Anzeige.

Gut... von mir falsch verstanden. Ihr meint die Icons?
Dann macht bitte ein ls -la /opt/fhem/www/images/tv

Und ein "list" vom DOIF kann sowieso nicht schaden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 13:05:19
ls: Zugriff auf '/opt/fhem/www/images/tv' nicht möglich: Datei oder Verzeichnis nicht gefunden
p

hätte ich dir aber auch so sagen können. Deshalb fragte ich ja, woher die Icons kommen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 13:06:34
Bei mir 1 zu 1 aus deinem ersten Beitrag kopiert.
Das verzeichnis /opt/fhem/www/images/tv  gab es bei mir nicht.
Da habe ich die logos von AVM hinkopiert.
Gruß

Carlos

Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 13:08:49
Ich habe da noch eine Zusatzfrage: Wo finde ich denn die Schreibweise des Senders, wenn ich das DOIF um Tele5 erweitern möchte?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 13:10:30
Zitat von: carlos am 14 Juni 2020, 13:06:34
Bei mir 1 zu 1 aus deinem ersten Beitrag kopiert.
Das verzeichnis /opt/fhem/www/images/tv  gab es bei mir nicht.
Da habe ich die logos von AVM hinkopiert.
Gruß

Carlos


Bitte ein "list" vom DOIF, damit man was sehen kann! "Bei mir 1 zu 1 aus deinem ersten Beitrag kopiert." bedeutet nicht, dass alles funktioniert wie gedacht. Man muss mindestens die Readings sehen.

Zitat von: Invers am 14 Juni 2020, 13:08:49
Ich habe da noch eine Zusatzfrage: Wo finde ich denn die Schreibweise des Senders, wenn ich das DOIF um Tele5 erweitern möchte?

HIer: http://epg.vuplus-community.net/rytec.channels.xml, bzw. in der entpackte .xml Datei (/opt/fhem/rytecDE_Basic) aus der .xz Datei in deinem Fhem Verzeichnis



Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 13:12:47
Bitte schön:
Internals:
   .AttrList  disable:0,1 loglevel:0,1,2,3,4,5,6 notexist checkReadingEvent:0,1 addStateEvent:1,0 weekdays setList:textField-long readingList DOIF_Readings:textField-long event_Readings:textField-long uiTable:textField-long event-aggregator event-min-interval event-on-change-reading event-on-update-reading oldreadings stateFormat:textField-long timestamp-on-change-reading
   DEF        subs
{
  use utf8;
  use Date::Parse;
  # sudo apt-get install libxml-bare-perl
  use XML::Bare 0.53 qw(forcearray);
  use Blocking;
 
  ### CONFIG AREA ###
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;
  # telnet port must not be password protected (open)
  $_telnetPort = 7072;
  $_timeAdjust = 0;
  $_path = '/opt/fhem/';
  $_dataFile = $_path.'rytecDE_Basic';
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)
  $_filterChannels = 1;
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)
  $_updateBasedOnStarttimes = 1;
 
  # internal variables
  $_startTimes;
 
  sub filterText($)
  {
    my $text = shift;

    $text =~ s/["`;'\r]//g;
    $text =~ s/[\n]/
/g;

    return $text;
  }
 
  sub xmltv2epoch($)
  {
    my $t = shift;

    return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;
  }

  sub FmtDateTime($)
  {
    my @t = localtime(shift);
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
  }

  sub tvParse($$)
  {
    my ($device, $mode) = @_;
    my $obj;
    my $xml;
    my $lastChannel = '';
    my $reading = '';
    my $i = 999;
    my $n = 999;
    my $k = 0;
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';
    my $sendTelnet = '';
   
    $obj = XML::Bare->new(file => $_dataFile);
    $xml = $obj->parse();

    if (!$@)
    {
      my $old = time() + $_timeAdjust;

      foreach (@{forcearray($xml->{'tv'}{'programme'})})
      {
        if ((0 != $_filterChannels) ||
            ($_->{'channel'}{'value'} =~ $_channelFilter))
        {
          my $stop = xmltv2epoch($_->{'stop'}{'value'});

          # filter old stuff
          if ($stop > $old)
          {
            if ($lastChannel ne $_->{'channel'}{'value'})
            {
              $lastChannel = $_->{'channel'}{'value'};
              $reading = $_->{'channel'}{'value'};
              $reading =~ s/[\.\s]//g;
              $reading =~ s/de$//;
              $n = 0;
             
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))
              {
                $i = 0;

                if (0 != $_updateBasedOnStarttimes)
                {
                  $_startTimes{$reading} = $stop;
                }
              }
            }

            if ($i < 3 && 'next' eq $mode)
            {
              my $fi = sprintf("%03d", $i);
              my $start = xmltv2epoch($_->{'start'}{'value'});
              my $readingName;
              my $readingValue;

              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';
              $readingValue = substr(FmtDateTime($start), 0, 10);
              $sendTelnet .= ";setreading $device $readingName $readingValue";

              $readingName = 'next_'.$reading.'_'.$fi.'_btime';
              $readingValue = substr(FmtDateTime($start), 11, 8);
              $sendTelnet .= ";setreading $device $readingName $readingValue";

              $readingName = 'next_'.$reading.'_'.$fi.'_title';
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});
              $sendTelnet .= ";setreading $device $readingName $readingValue";

              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';
              if (exists($_->{'sub-title'}{'value'}))
              {
                $readingValue = filterText($_->{'sub-title'}{'value'});
              }
              else
              {
                $readingValue = 'na';
              }
              $sendTelnet .= ";setreading $device $readingName $readingValue";

              $readingName = 'next_'.$reading.'_'.$fi.'_desc';
              if (exists($_->{'desc'}{'value'}))
              {
                $readingValue = filterText($_->{'desc'}{'value'});
              }
              else
              {
                $readingValue = 'na';
              }
              $sendTelnet .= ";setreading $device $readingName $readingValue";

              $k++;
              $i++;
            }

            if ($n < 3 && 'prime' eq $mode)
            {
              my $start = xmltv2epoch($_->{'start'}{'value'});
              my $fmtStart = FmtDateTime($start);
              my $bdate = substr($fmtStart, 0, 10);
              my $btime = substr($fmtStart, 11, 8);

              if ($bdate.' '.$btime gt $primeTime)
              {
                my $fn = sprintf("%03d", $n);
                my $readingName;
                my $readingValue;

                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';
                $readingValue = substr(FmtDateTime($start), 0, 10);
                $sendTelnet .= ";setreading $device $readingName $readingValue";

                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';
                $readingValue = substr(FmtDateTime($start), 11, 8);
                $sendTelnet .= ";setreading $device $readingName $readingValue";

                $readingName = 'prime_'.$reading.'_'.$fn.'_title';
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});
                $sendTelnet .= ";setreading $device $readingName $readingValue";

                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';
                if (exists($_->{'sub-title'}{'value'}))
                {
                  $readingValue = filterText($_->{'sub-title'}{'value'});
                }
                else
                {
                  $readingValue = 'na';
                }
                $sendTelnet .= ";setreading $device $readingName $readingValue";

                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';
                if (exists($_->{'desc'}{'value'}))
                {
                  $readingValue = filterText($_->{'desc'}{'value'});
                }
                else
                {
                  $readingValue = 'na';
                }
                $sendTelnet .= ";setreading $device $readingName $readingValue";

                $k++;
                $n++;
              }
            }

            if ($k >= 10)
            {
              `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;

              $k = 0;
              $sendTelnet = '';
            }
          }
        }
      }

      if ('' ne $sendTelnet)
      {
        `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;
      }
    }
   
    return %{$_startTimes};
  }
 
  sub tvMerge($;$)
  {
    my ($dstName, $srcName) = @_;
    my $fh;
    my $dst;
    my $src;
    my $start = '';
    my $channels1 = '';
    my $channels1_flt = '';
    my $channels2 = '';
    my $channels2_flt = '';
    my $programms1 = '';
    my $programms1_flt = '';
    my $programms2 = '';
    my $programms2_flt = '';
    my $end = '';
    my $pos;

    open($fh, '<', $dstName) or die "Can't open file $!";
    read($fh, $dst, -s $fh);
    close($fh);

    if (defined($srcName))
    {
      open($fh, '<', $srcName) or die "Can't open file $!";
      read($fh, $src, -s $fh);
      close($fh);
    }

    if (-1 != ($pos = index($dst, '
    {
      $start = substr($dst, 0, $pos);
    }

    if (-1 != ($pos = rindex($dst, '')))
    {
      $end = substr($dst, $pos + 12);
    }

    while ($dst =~ /(\s*)/sg)
    {
      if (0 != $_filterChannels)
      {
        $_ = $1;

        if ($2 =~ $_channelFilter)
        {
          $channels1_flt .= $_;
        }
      }
      else
      {
        $channels1 .= $1;
      }
    }

    while ($dst =~ /(\s*)/sg)
    {
      if (0 != $_filterChannels)
      {
        $_ = $1;

        if ($2 =~ $_channelFilter)
        {
          $programms1_flt .= $_;
        }
      }
      else
      {
        $programms1 .= $1;
      }
    }

    if (defined($srcName))
    {
      while ($src =~ /(\s*)/sg)
      {
        if (0 != $_filterChannels)
        {
          $_ = $1;

          if ($2 =~ $_channelFilter)
          {
            $channels2_flt .= $_;
          }
        }
        else
        {
          $channels2 .= $1;
        }
      }

      while ($src =~ /(\s*)/sg)
      {
        if (0 != $_filterChannels)
        {
          $_ = $1;

          if ($2 =~ $_channelFilter)
          {
            $programms2_flt .= $_;
          }
        }
        else
        {
          $programms2 .= $1;
        }
      }
    }

    if (0 != $_filterChannels)
    {
      open($fh, '>', $dstName) or die "Can't open file $!";

      if (defined($srcName))
      {
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;
      }
      else
      {
        print $fh $start.$channels1_flt.$programms1_flt.$end;
      }

      close($fh);
    }
    else
    {
      open($fh, '>', $dstName) or die "Can't open file $!";

      if (defined($srcName))
      {
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;
      }
      else
      {
        print $fh $start.$channels1.$programms1.$end;
      }

      close($fh);
    }
  }

  sub tvDownload()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);

    if (0 != $_filterChannels)
    {
      tvMerge($_dataFile);
    }
   
    return $output;
  }

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');

    # download and merge other files here if needed
   
    return $output;
  }
 
 
  sub startDownload($)
  {
    my $name = shift;
   
    if (defined($_blockingcalls{PID_DOWNLOAD}))
    {
      ::Log3 $name, 3, $name.': Blocking call already running (download).';

      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});
    }

    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);
  }
 
  sub DOIF::doDownload($)
  {
    my $name = shift;
    my $output = '';
   
    $output = tvDownloadMerge();
   
    return $name.'|'.$output;
  }
 
  sub DOIF::endDownload($)
  {
    my ($name, $output) = split("\\|", shift);
   
    ::Log3 $name, 5, $name.': Blocking call finished to download tv data.';
   
    delete($_blockingcalls{PID_DOWNLOAD});
  }
 
  sub DOIF::abortDownload($)
  {
    my $name = shift;
   
    delete($_blockingcalls{PID_DOWNLOAD});
   
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';
  }
 
  sub startParse($$)
  {
    my ($name, $mode) = @_;
   
    if (defined($_blockingcalls{PID_PARSE}))
    {
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';

      ::BlockingKill($_blockingcalls{PID_PARSE});
    }
   
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);
  }
 
  sub DOIF::doParse($)
  {
    my ($name, $mode) = split("\\|", shift);
    my $ret = $name;
    my %startTimes = tvParse($name, $mode);
   
    foreach (keys(%startTimes))
    {
      $ret .= '|'.$_.'|'.$startTimes{$_};
    }
   
    return $ret;
  }
 
  sub DOIF::endParse($)
  {
    my ($name, @startTimes) = split("\\|", shift);
       
    for (my $i = 0; $i < (scalar(@startTimes) / 2); $i += 2)
    {
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];
    }
   
    ::Log3 $name, 5, $name.': Blocking call finished to parse tv data.';
   
    delete($_blockingcalls{PID_PARSE});
  }
 
  sub DOIF::abortParse($)
  {
    my $name = shift;
   
    delete($_blockingcalls{PID_PARSE});
   
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';
  }
}
init
{
  startDownload("$SELF");
}
{
  if ([00:05|Mo Do])
  {
    startDownload("$SELF");
  }
 
  if ([+00:15])
  {
    startParse("$SELF", 'next');
  }
 
  if ([00:30])
  {
    startParse("$SELF", 'prime');
  }
}
   FUUID      5ee4d44e-f33f-1bd0-959b-382f89c29093bb99
   MODEL      Perl
   NAME       doif_TEST
   NOTIFYDEV  doif_TEST,global
   NR         1507
   NTFY_ORDER 50-doif_TEST
   STATE      ???
   TYPE       DOIF
   VERSION    22161 2020-06-11 12:49:48
   .attraggr:
   .attrminint:
   READINGS:
     2020-06-14 13:05:46   block_02        executed
     2020-06-14 11:12:28   block_init      executed
     2020-06-13 23:28:00   mode            enabled
     2020-06-14 13:07:52   next_13thStreet_000_bdate 2020-06-14
     2020-06-14 13:07:52   next_13thStreet_000_btime 13:05:00
     2020-06-14 13:07:52   next_13thStreet_000_desc Gibbs und Ducky sehen in einer Fernsehshow eine antike Kriegswaffe einen Knüppel mit Dornen. Sie sind überzeugt dass es sich dabei um die Mordwaffe in einem 16 Jahre alten ungelösten Fall handelt. Ducky kehrt mit seiner Assistentin Kasie zurück in die Stadt um den Fall aufzuklären. Das Team versucht mit der Hilfe des Trödelsammlers Mike Wolfe den früheren Besitzer der Waffe aufzuspüren.
Michael Zinberg
Mark Harmon
David L. McCallum
Pauley Perrette
Sean Murray
Brian Dietzen
Emily Wickersham
Maria Bello
Wilmer Valderrama
Duane Henry
Rocky Carroll
Diona Reasonover
Mike Wolfe
Kamal Angelo Bolden
Alyson Reed
Clark Freeman
Leonard Kelly-Young
Shireen Crutchfield
Ana Rey
Jorga Caye
     2020-06-14 13:07:52   next_13thStreet_000_stitle (NCIS: Naval Criminal Investigative Service)Das Museum der Morde (2018) [12+]
     2020-06-14 13:07:52   next_13thStreet_000_title Navy CIS
     2020-06-14 13:07:52   next_13thStreet_001_bdate 2020-06-14
     2020-06-14 13:07:52   next_13thStreet_001_btime 13:50:00
     2020-06-14 13:07:52   next_13thStreet_001_desc Auf das NCIS-Team werden Anschläge verübt. Gibbs entkommt im Iran nur knapp einem Attentat DiNozzo gerät in Lebensgefahr und Ziva muss in Israel untertauchen wo sie ein neues Leben beginnen will. Als sich auf einem Militärstützpunkt mehr als dreissig Kinder mit einer rätselhaften Krankheit infizieren arbeiten Abby und Jimmy fieberhaft daran den Erreger zu identifizieren und den Fall zu lösen.
Rocky Carroll
Mark Harmon
David McCallum
Pauley Perrette
Sean Murray
Brian Dietzen
Emily Wickersham
Wilmer Valderrama
Maria Bello
Duane Henry
Rocky Carroll
Robert Wagner
Ty Olsson
Gwendoline Yeo
Ian Verdun
Nalini Sharma
     2020-06-14 13:07:52   next_13thStreet_001_stitle (NCIS: Naval Criminal Investigative Service)Die Leiche auf dem Dach (2018) [12+]
     2020-06-14 13:07:52   next_13thStreet_001_title Navy CIS
     2020-06-14 13:07:52   next_13thStreet_002_bdate 2020-06-14
     2020-06-14 13:07:52   next_13thStreet_002_btime 14:35:00
     2020-06-14 13:07:52   next_13thStreet_002_desc Nachdem die Leichen zweier Männer gefunden wurden von denen einer zuvor einen falschen Ausweis für einen Marine Sergeant ausgestellt hatte nimmt das NCIS-Team die Ermittlungen auf. Die Spur führt zu einer Gruppe von Flüchtlingskindern die vorübergehend in einer Militärbasis untergebracht wurden. Gibbs nimmt ein zehnjähriges Mädchen in seine Obhut das offenbar im Visier einer Bande ist.
Leslie Libman
Mark Harmon
David McCallum
Pauley Perrette
Sean Murray
Brian Dietzen
Emily Wickersham
Wilmer Valderrama
Duane Henry
Maria Bello
Rocky Carroll
Daniel Steven Gonzalez
Luis Jose Lopez
Alexis Carra
Lily Rose Silver
Matty Cardarople
R.M. Armas
Hans Marrero
Jessen Noviello
     2020-06-14 13:07:52   next_13thStreet_002_stitle (NCIS: Naval Criminal Investigative Service)Eiskalte Waffen (2018) [16+]
     2020-06-14 13:07:52   next_13thStreet_002_title Navy CIS
     2020-06-14 12:47:03   next_ARD_000_bdate 2020-06-14
     2020-06-14 12:47:03   next_ARD_000_btime 12:45:00
     2020-06-14 12:47:03   next_ARD_000_desc Das wöchentliche Magazin will schwierige politische Prozesse und komplexe Probleme Europas erklären aber auch fremde Mentalitäten und Perspektiven zeigen
     2020-06-14 12:47:03   next_ARD_000_stitle [Auslandsmagazin, Europa] Bericht aus Brüssel (2020)
     2020-06-14 12:47:03   next_ARD_000_title Europamagazin
     2020-06-14 12:47:03   next_ARD_001_bdate 2020-06-14
     2020-06-14 12:47:03   next_ARD_001_btime 13:15:00
     2020-06-14 12:47:03   next_ARD_001_desc Im Norden Europas ist der Seeadler heimisch der Gegenden mit Wäldern Seen und Sümpfe bevorzugt. In Deutschland kann man Seeadler im wasserreichen Nordosten beobachten. Der Film zeigt die Vögel auf einer von Kormoranen besiedelten Insel wo sie einen günstigen Lebensraum vorfinden. Ideal wäre allerdings eine Wildnis in der die Adler vom Jagdglück der Wölfe und Bären profitieren könnten.
Alastair Fothergill
     2020-06-14 12:47:03   next_ARD_001_stitle [Tierdokumentation, Tiere]  (2014)
     2020-06-14 12:47:03   next_ARD_001_title Seeadler - Der Vogel Phönix
     2020-06-14 12:47:03   next_ARD_002_bdate 2020-06-14
     2020-06-14 12:47:03   next_ARD_002_btime 14:00:00
     2020-06-14 12:47:03   next_ARD_002_desc Aktuelle Themen aus Politik Wirtschaft Kultur Sport Gesellschaft und Wissenschaft aus dem In- und Ausland werden in ausführlichen Hintergrundberichten beleuchtet. In Stellungnahmen und Meinungsäusserungen wird auch unterschiedlichne Standpunkten Raum gegeben
     2020-06-14 12:47:03   next_ARD_002_stitle Mit Wetter
     2020-06-14 12:47:03   next_ARD_002_title Tagesschau
     2020-06-14 13:07:52   next_AXN_000_bdate 2020-06-14
     2020-06-14 13:07:52   next_AXN_000_btime 12:45:00
     2020-06-14 13:07:52   next_AXN_000_desc Als Jack Dwyer von seiner Firma die Leitung einer Wasseraufbereitungsanlage in Südostasien angeboten bekommt ergreift er die Gelegenheit und zieht mit seiner Familie um. Schon bei ihrer Ankunft bemerken die Dwyers dass etwas nicht stimmt. Als Jack in einen Aufstand von Rebellen gerät die es auf Ausländer abgesehen haben flüchtet er zurück ins Hotel um seine Familien in Sicherheit zu bringen.
John Erick Dowdle
Owen Wilson
Lake Bell
Pierce Brosnan
Sterling Jerins
Claire Geare
Sahajak Boonthanakit
Thanawut Ketsaro
Chatchawai Kamonsakpitak
Tanapol Chuksrida
Nophand Boonyai
Kanarpat Phintiang
Jon Goldney
Duang Maidork
Suphornnaphat Jenselius
Barthélemy Son
Mikayla Friend
Stacy Chbosky
Thanawat Kaewarkorn
Spencer Garrett
     2020-06-14 13:07:52   next_AXN_000_stitle [Actionthriller]  (2015) [16+]
     2020-06-14 13:07:52   next_AXN_000_title No Escape
     2020-06-14 13:07:52   next_AXN_001_bdate 2020-06-14
     2020-06-14 13:07:52   next_AXN_001_btime 14:30:00
     2020-06-14 13:07:52   next_AXN_001_desc Der junge Bauarbeiter Dennis Nash arbeitet hart um für seine Mutter und seinen Sohn Connor zu sorgen. Nach einer versäumten Zahlung kommt es jedoch zur Zwangsräumung und von einem auf den anderen Tag steht Dennis mit seiner Familie auf der Strasse. Um sein Zuhause zurückzugewinnen ist Dennis zu allem bereit und nimmt ein dubioses Jobangebot des skrupellosen Immobilienmaklers Rick Carver an.
Ramin Bahrani
Andrew Garfield
Michael Shannon
Laura Dern
Tim Guinee
Noah Lomax
Clancy Brown
Randy Austin
Cullen Moss
Doug Griffin
Carl Palmer
James Brown
Luke Sexton
Alex Aristidis
Jonathan Tabler
Garrett Kruithof
Richard Holden
Deneen Tyler
Albert C. Bates
Jayson Warner Smith
     2020-06-14 13:07:52   next_AXN_001_stitle (2014) [12+]
     2020-06-14 13:07:52   next_AXN_001_title 99 Homes
     2020-06-14 13:07:52   next_AXN_002_bdate 2020-06-14
     2020-06-14 13:07:52   next_AXN_002_btime 16:30:00
     2020-06-14 13:07:52   next_AXN_002_desc Atlanta ist schwer vom Verbrechen gebeutelt Strassenschlachten öffentlichen Hinrichtung und brutaler Folter mit denen die übermächtige Russenmafia ihre Vorherrschaft deutlich macht. Für viele Cops bieten sich verführerische Möglichkeiten - Zu den korrupten Polizisten gehört auch Marcus Atwood der gar nicht begeistert ist als man ihm als Partner den Frischling Chris zur Seite stellt...
John Hillcoat
Casey Affleck
Chiwetel Ejiofor
Anthony Mackie
Aaron Paul
Norman Reedus
Kate Winslet
Woody Harrelson
Clifton Collins Jr.
Gal Gadot
Teresa Palmer
Michelle Ang
Luis Da Silva Jr.
E. Roger Mitchell
Carlos Aviles
Michael Harding
Susanne Marie Danger
Natalie Shaheen
Valiant Michael
Mary Rachel Quinn
     2020-06-14 13:07:52   next_AXN_002_stitle [Krimidrama]  (Triple Nine) (2016) [16+]
     2020-06-14 13:07:52   next_AXN_002_title Triple 9
     2020-06-14 13:06:22   next_AandE_000_bdate 2020-06-14
     2020-06-14 13:06:22   next_AandE_000_btime 12:35:00
     2020-06-14 13:06:22   next_AandE_000_desc Die Doku-Reihe Evil Twins taucht ein in echte schockierende Zwillings-Kriminalfälle wie jener eines weiblichen Zwillings der den Ehemann ihrer Schwester verführte und ein Mordkomplott ausheckte oder jener Fall bei dem der eine Zwilling die Identität des anderen annahm.
Jen Ayer Drake
Tony Barber
Matt Gulbranson
Andrew Patrick LaHaise
Robert Olausen
Janae Palmer
Chaz Riddle
Meg Scanlon
Arthur Titus
Brannon Titus
Daniel Wagner.
     2020-06-14 13:06:22   next_AandE_000_stitle [Doku-Serie, Recht + Kriminalität]  (Evil Twins)William und Christopher Cormier (2017) [16+]
     2020-06-14 13:06:22   next_AandE_000_title Evil Twins - Böse Zwillinge
     2020-06-14 13:06:22   next_AandE_001_bdate 2020-06-14
     2020-06-14 13:06:22   next_AandE_001_btime 13:25:00
     2020-06-14 13:06:22   next_AandE_001_desc Der Serienmörder Ted Bundy tötete in den 1970er-Jahren mindestens 30 Frauen und Mädchen. Die Morde hatten ihren Ursprung in seiner persönlichen Geschichte einer Kindheit ohne Vater und einer Mutter die sich als Teds Schwester ausgab. Bundy beging seine Verbrechen stets bei Nacht und an den meisten Tatorten wurde ein Mann gesichtet der einen Gips oder eine Schlinge trug und einen Käfer fuhr.
     2020-06-14 13:06:22   next_AandE_001_stitle [Recht + Kriminalität]  (Ted Bundy: Serial Monster)Wurzeln des Bösen (2018) [16+]
     2020-06-14 13:06:22   next_AandE_001_title Ted Bundy - Ein Wolf im Schafspelz
     2020-06-14 13:06:22   next_AandE_002_bdate 2020-06-14
     2020-06-14 13:06:22   next_AandE_002_btime 14:15:00
     2020-06-14 13:06:22   next_AandE_002_desc Kurz nach Teds Umzug nach Salt Lake City beginnt in der Gegend eine neue Mordserie.
     2020-06-14 13:06:22   next_AandE_002_stitle [Recht + Kriminalität]  (Ted Bundy: Serial Monster)Perfide Masche (2018) [16+]
     2020-06-14 13:06:22   next_AandE_002_title Ted Bundy - Ein Wolf im Schafspelz
     2020-06-14 12:47:04   next_AnimalPlanet_000_bdate 2020-06-14
     2020-06-14 12:47:04   next_AnimalPlanet_000_btime 12:40:00
     2020-06-14 12:47:04   next_AnimalPlanet_000_desc Groß, größer, am größten! Handelsübliche Zimmer-Aquarien sind auch nett, doch mit 10-Liter-Becken haben Wayde King und sein Partner Brett Raymer wenig am Hut. Ihr Spezialgebiet sind atemberaubende Unterwasserwelten! Vom achteckigen Ökosystem mit Muränen und Stachelrochen über das Telefonzellen-Aquarium bis zum Haifisch-Tank für die Arztpraxis: Es gibt fast keine Idee, an die sich die Jungs nicht herantrauen. Dementsprechend lautet das Motto der beiden New Yorker: Wovon andere träumen, setzen wir in die Tat um! Und ihre Super-Aquarien gefallen nicht nur den Unterwasserbewohnern ausgesprochen gut, sondern auch dem Publikum. Wo immer Brett und Wayde ihre beeindruckenden Spezialanfertigungen der Öffentlichkeit präsentieren, kommen die Leute aus dem Staunen nicht heraus
     2020-06-14 12:47:04   next_AnimalPlanet_000_stitle Reality-Soap
     2020-06-14 12:47:04   next_AnimalPlanet_000_title Die Aquarium-Profis: Episode 2
     2020-06-14 12:47:04   next_AnimalPlanet_001_bdate 2020-06-14
     2020-06-14 12:47:04   next_AnimalPlanet_001_btime 13:25:00
     2020-06-14 12:47:04   next_AnimalPlanet_001_desc Groß, größer, am größten! Handelsübliche Zimmer-Aquarien sind auch nett, doch mit 10-Liter-Becken haben Wayde King und sein Partner Brett Raymer wenig am Hut. Ihr Spezialgebiet sind atemberaubende Unterwasserwelten! Vom achteckigen Ökosystem mit Muränen und Stachelrochen über das Telefonzellen-Aquarium bis zum Haifisch-Tank für die Arztpraxis: Es gibt fast keine Idee, an die sich die Jungs nicht herantrauen. Dementsprechend lautet das Motto der beiden New Yorker: Wovon andere träumen, setzen wir in die Tat um! Und ihre Super-Aquarien gefallen nicht nur den Unterwasserbewohnern ausgesprochen gut, sondern auch dem Publikum. Wo immer Brett und Wayde ihre beeindruckenden Spezialanfertigungen der Öffentlichkeit präsentieren, kommen die Leute aus dem Staunen nicht heraus
     2020-06-14 12:47:04   next_AnimalPlanet_001_stitle Reality-Soap
     2020-06-14 12:47:04   next_AnimalPlanet_001_title Die Aquarium-Profis: Episode 3
     2020-06-14 12:47:07   next_AnimalPlanet_002_bdate 2020-06-14
     2020-06-14 12:47:07   next_AnimalPlanet_002_btime 14:10:00
     2020-06-14 12:47:08   next_AnimalPlanet_002_desc Tansania, Ostafrika: Rund 30 Kilometer vom Festland entfernt befindet sich ein tropisches Inselparadies mit traumhaften Stränden, üppigem Regenwald und einer lebendigen afrikanischen Kultur. Die Rede ist von Sansibar! Einst lebte hier ein geschickter Räuber, dem sogar mystische Kräfte nachgesagt werden - der Sansibar-Leopard oder Panthera pardus adersi. Doch seit 25 Jahren gilt diese außergewöhnliche Raubkatze als ausgestorben. Dank akribischer Recherche vor Ort und mit der Hilfe einheimischer Nationalpark-Ranger gelingt Wildtierbiologe Forrest Galante eine doppelte Sensation: Er findet heraus, dass der Sansibar-Leopard noch lebt und liefert den einzigartigen Videobeweis gleich dazu.
     2020-06-14 12:47:08   next_AnimalPlanet_002_stitle Dokumentation
     2020-06-14 12:47:08   next_AnimalPlanet_002_title Extinct Or Alive - Ausgestorben oder nicht?: Der Sansibar-Leopard
     2020-06-14 13:06:10   next_DMax_000_bdate 2020-06-14
     2020-06-14 13:06:10   next_DMax_000_btime 12:50:00
     2020-06-14 13:06:11   next_DMax_000_desc Baustoffe, Heizmaterial, Lebensmittel: Pro Jahr werden in Shoreham am Ärmelkanal zwei Millionen Tonnen Fracht umgeschlagen. Aber so etwas wie Alltag gibt es im Hafen nicht. Jeder Auftrag ist anders und unvorhergesehene Zwischenfälle gehören zum Geschäft. Heute sollen 5.000 Tonnen zerhäckseltes Holz nach Schweden verschifft werden. Dort verfeuern Heizkraftwerke den Biomassebrennstoff später zu Wärme und Strom. Bevor die Ware an Bord kann, muss allerdings erst der 95 Meter lange Schüttgutfrachter Kamelia durch die schmale Schleuse von Shoreham. Lotsen und Lademeister sind bereits zur Stelle. Doch plötzlich bringt eine Staubwolke aus Sägespänen die Arbeiter und ihre Maschinen in Gefahr
     2020-06-14 13:06:10   next_DMax_000_stitle Dokumentation
     2020-06-14 13:06:10   next_DMax_000_title Mega Shippers - Die Profis vom Frachthafen: Episode 15
     2020-06-14 13:06:11   next_DMax_001_bdate 2020-06-14
     2020-06-14 13:06:11   next_DMax_001_btime 13:45:00
     2020-06-14 13:06:11   next_DMax_001_desc Die Saison neigt sich dem Ende entgegen und Kelly Tishler setzt in Australien alles auf eine Karte. Ihre Geldreserven sind vollkommen aufgebraucht, deshalb muss die Schatzsucherin einen umgebauten Betonmischer verkaufen, um in Lightning Ridge eine weitere Probebohrung zu finanzieren. Dabei hat es die Edelstein-Expertin auf Schwarze Opale abgesehen, die pro Gramm bis zu 175 000 Dollar einbringen können. Die Boulder Boys geben auf der Zielgeraden ebenfalls Vollgas. Und die harte Plackerei auf dem Dragonfly-Claim zahlt sich für die Glücksritter aus
     2020-06-14 13:06:11   next_DMax_001_stitle Reality-Soap
     2020-06-14 13:06:11   next_DMax_001_title Outback Opal Hunters - Edelsteinjagd in Australien: Ende gut, alles gut
     2020-06-14 13:06:11   next_DMax_002_bdate 2020-06-14
     2020-06-14 13:06:11   next_DMax_002_btime 14:40:00
     2020-06-14 13:06:11   next_DMax_002_desc Unter der Erdoberfläche des australischen Kontinents verbirgt sich ein kostbarer Schatz: Opale. Die funkelnden Juwelen können Schatzsucher über Nacht zu Millionären machen. Aber die Jagd nach den Edelsteinen ist im Outback mit großen Risiken und Gefahren verbunden. In der kargen Wüstenlandschaft bekommen es die Abenteurer mit extremer Hitze und ungebetenen Eindringlingen zu tun. Rod Manning und Les Walsh verfolgen zum Auftakt der neuen Staffel mit ihrem Jeep in der Dunkelheit dreiste Claim-Räuber, die sich auf Kosten anderer bereichern wollen
     2020-06-14 13:06:11   next_DMax_002_stitle Reality-Soap
     2020-06-14 13:06:11   next_DMax_002_title Outback Opal Hunters - Edelsteinjagd in Australien: Angriff auf den Claim
     2020-06-14 12:47:08   next_History_000_bdate 2020-06-14
     2020-06-14 12:47:08   next_History_000_btime 12:35:00
     2020-06-14 12:47:08   next_History_000_desc Etwas unaussprechlich Böses quält die jungen Mädchen in Reverend Samuel Parris Haushalt und verbreitet sich wie eine Seuche rasend schnell in der Stadt Salem. Es sieht so aus als sei die fromme Gemeinde vom Teufel persönlich heimgesucht worden.
Chayla Day
Kyla Despres
Kayla Jo Farris
Adam Jenner
Lisa Kovack
Quinton Neufeldt
Kasey Nugent
David Parisian
Aundreya Thompson
James J. Wilson
Sylvain Plasse
     2020-06-14 12:47:08   next_History_000_stitle [Doku-Serie]  (Witches Of Salem)Gottlos (2019) [12+]
     2020-06-14 12:47:08   next_History_000_title Witches of Salem
     2020-06-14 12:47:08   next_History_001_bdate 2020-06-14
     2020-06-14 12:47:08   next_History_001_btime 13:30:00
     2020-06-14 12:47:08   next_History_001_desc Die Paranoia erreicht ihren Höhepunkt und die dämonische Verschwörungstherorie die Salem terrorisiert verschont niemanden. Das Gefängnis von Boston füllt sich mit Frauen und Mädchen die unter Verdacht stehen Hexen zu sein und den Angeklagten steht die Hinrichtung bevor wenn sie für schuldig befunden werden.
Chayla Day
Kyla Despres
Kayla Jo Farris
David Parisian
Sylvain Plasse
     2020-06-14 12:47:08   next_History_001_stitle [Doku-Serie]  (Witches Of Salem)Paranoia (2019) [12+]
     2020-06-14 12:47:08   next_History_001_title Witches of Salem
     2020-06-14 12:47:08   next_History_002_bdate 2020-06-14
     2020-06-14 12:47:08   next_History_002_btime 14:25:00
     2020-06-14 12:47:08   next_History_002_desc Wer ist der bessere Fussballer Cristiano Ronaldo oder Lionel Messi? Ein Expertengremium wird entscheiden
     2020-06-14 12:47:08   next_History_002_stitle [Fussball, Sonstige]  (Historys Greatest Players - Head to Head)Cristiano Ronaldo vs. Lionel Messi (2018) [12+]
     2020-06-14 12:47:08   next_History_002_title Superstars des Fussballs - Rivalen auf dem Rasen
     2020-06-14 12:47:00   next_KabelEinsClassic_000_bdate 2020-06-14
     2020-06-14 12:47:00   next_KabelEinsClassic_000_btime 12:35:00
     2020-06-14 12:47:00   next_KabelEinsClassic_000_desc Anfang des 20. Jahrhunderts teilen in Italien politische Differenzen die Bevölkerung in rivalisierende Klassen. Neben den Sozialisten entwickeln sich faschistische Tendenzen. In diesem Klima werden zeitgleich zwei Jungen geboren: Alfredo und Olmo. Beide stammen aus Familien, die unterschiedlicher nicht sein könnten - trotzdem werden sie Freunde. Sie teilen ihre Jugend miteinander, doch der Ausbruch des Ersten Weltkrieges stellt ihre Freundschaft auf die Probe
     2020-06-14 12:47:00   next_KabelEinsClassic_000_stitle Drama
     2020-06-14 12:47:00   next_KabelEinsClassic_000_title 1900 - Gewalt, Macht, Leidenschaft (1)
     2020-06-14 12:47:00   next_KabelEinsClassic_001_bdate 2020-06-14
     2020-06-14 12:47:00   next_KabelEinsClassic_001_btime 15:15:00
     2020-06-14 12:47:01   next_KabelEinsClassic_001_desc Fortsetzung von Bernardo Bertoluccis monumentalem Historiendrama 1900: Die faschistischen Schwarzhemden gewinnen die politische Obermacht in Italien. Die beiden Freunde Alfredo und Olmo finden sich auf der Seite zweier politischer Fronten wieder. Beide durchleben die Jahre bis zu den Befreiungsfeiern im Jahr 1945. Der eine als politisch aktiver Sozialist, der andere als politisch konservativer Lebemann
     2020-06-14 12:47:01   next_KabelEinsClassic_001_stitle Drama
     2020-06-14 12:47:00   next_KabelEinsClassic_001_title 1900 - Kampf, Liebe, Hoffnung (2)
     2020-06-14 12:47:01   next_KabelEinsClassic_002_bdate 2020-06-14
     2020-06-14 12:47:01   next_KabelEinsClassic_002_btime 17:45:00
     2020-06-14 12:47:01   next_KabelEinsClassic_002_desc Während sich John Blackthorne und Fürst Soranaga weiter annähern, planen die Jesuiten, den Seemann zu töten. Schon kurz darauf wird er von einem Unbekannten angegriffen. Doch auch Soranaga schmiedet Pläne: Er will von Schloss Osaka fliehen .
     2020-06-14 12:47:01   next_KabelEinsClassic_002_stitle Abenteuerserie
     2020-06-14 12:47:01   next_KabelEinsClassic_002_title Shogun
     2020-06-14 13:06:11   next_KabelEinsDoku_000_bdate 2020-06-14
     2020-06-14 13:06:11   next_KabelEinsDoku_000_btime 13:00:00
     2020-06-14 13:06:11   next_KabelEinsDoku_000_desc Seit mehr als 10.000 Jahren errichtet der Mensch Bauwerke. Doch dabei wurde manchmal auch gepfuscht: Baukatastrophen weltweit enthüllt die größten Fehler und Missgeschicke der Ingenieurskünste auf der ganzen Welt. Dabei wird außerdem analysiert, was genau falsch lief, warum so manch schwerwiegender Fauxpas bislang unentdeckt blieb und natürlich, wie verheerende Folgen vermieden werden können
     2020-06-14 13:06:11   next_KabelEinsDoku_000_stitle Dokumentation
     2020-06-14 13:06:11   next_KabelEinsDoku_000_title Baukatastrophen weltweit: Gefährliches Baseballspiel
     2020-06-14 13:06:11   next_KabelEinsDoku_001_bdate 2020-06-14
     2020-06-14 13:06:11   next_KabelEinsDoku_001_btime 13:50:00
     2020-06-14 13:06:11   next_KabelEinsDoku_001_desc Seit mehr als 10.000 Jahren errichtet der Mensch Bauwerke. Doch dabei wurde manchmal auch gepfuscht: Baukatastrophen weltweit enthüllt die größten Fehler und Missgeschicke der Ingenieurskünste auf der ganzen Welt. Dabei wird außerdem analysiert, was genau falsch lief, warum so manch schwerwiegender Fauxpas bislang unentdeckt blieb und natürlich, wie verheerende Folgen vermieden werden können
     2020-06-14 13:06:11   next_KabelEinsDoku_001_stitle Dokumentation
     2020-06-14 13:06:11   next_KabelEinsDoku_001_title Baukatastrophen weltweit: Ein Stadtarchiv geht unter
     2020-06-14 13:06:11   next_KabelEinsDoku_002_bdate 2020-06-14
     2020-06-14 13:06:11   next_KabelEinsDoku_002_btime 14:40:00
     2020-06-14 13:06:11   next_KabelEinsDoku_002_desc Seit mehr als 10.000 Jahren errichtet der Mensch Bauwerke. Doch dabei wurde manchmal auch gepfuscht: Baukatastrophen weltweit enthüllt die größten Fehler und Missgeschicke der Ingenieurskünste auf der ganzen Welt. Dabei wird außerdem analysiert, was genau falsch lief, warum so manch schwerwiegender Fauxpas bislang unentdeckt blieb und natürlich, wie verheerende Folgen vermieden werden können
     2020-06-14 13:06:11   next_KabelEinsDoku_002_stitle Dokumentation
     2020-06-14 13:06:11   next_KabelEinsDoku_002_title Baukatastrophen weltweit: Flammeninferno im Tankdepot
     2020-06-14 11:27:28   next_Kabel_000_bdate 2020-06-14
     2020-06-14 11:27:28   next_Kabel_000_btime 11:20:00
     2020-06-14 11:27:28   next_Kabel_000_desc Zum Winteranfang fährt Tamme Hanken mit seiner Gattin Carmen nach Österreich. Bei seinem Weg in die Alpen stattet er einem Wolfsrudel im niedersächsischen Springe einen Besuch ab und schaut auf einer außergewöhnlichen Rentieralm an der Nahe vorbei. In Österreich angekommen, erlebt er auf dem Hintertuxer Gletscher in knapp 3.000 Metern Höhe einen Sammeltermin mit fünf Hunden. Außerdem bringt Tamme zwei edle Lipizzaner wieder auf Trab .
     2020-06-14 11:27:28   next_Kabel_000_stitle Dokumentation
     2020-06-14 11:27:28   next_Kabel_000_title Tamme Hanken - Der Knochenbrecher on tour: Österreich
     2020-06-14 11:27:28   next_Kabel_001_bdate 2020-06-14
     2020-06-14 11:27:28   next_Kabel_001_btime 13:15:00
     2020-06-14 11:27:28   next_Kabel_001_desc Abenteuer Leben Spezial begibt sich diesmal auf die Suche nach den verrücktesten Meisterschaften weltweit. Dafür geht es unter anderem nach Luxemburg zur Koch-WM, zur Barbecue-Weltmeisterschaft in die USA und zur Bodypainting-Weltmeisterschaft 2018 in Klagenfurt
     2020-06-14 11:27:28   next_Kabel_001_stitle Infomagazin
     2020-06-14 11:27:28   next_Kabel_001_title Abenteuer Leben Spezial - Die verrücktesten Meisterschaften weltweit
     2020-06-14 11:27:28   next_Kabel_002_bdate 2020-06-14
     2020-06-14 11:27:28   next_Kabel_002_btime 15:10:00
     2020-06-14 11:27:28   next_Kabel_002_desc Auf der Suche nach neuen Geschmackserlebnissen begibt sich Spitzenkoch Mike Süsser diese Woche nach Düsseldorf. Er startet im Stadtteil Unterbilk. Hier befindet sich das Robs Kitchen. Gastgeber Robert Rob Op den Kamp (41) verwöhnt seine Gäste mit innovativen Speisen in einer international ausgerichteten Kreativküche. Wird er mit seinem Know-how auch den Profi und seine Mitstreiter überzeugen können
     2020-06-14 11:27:28   next_Kabel_002_stitle Kochshow
     2020-06-14 11:27:28   next_Kabel_002_title Mein Lokal, Dein Lokal - Der Profi kommt: Restaurant Robs Kitchen, Düsseldorf
     2020-06-14 13:06:22   next_Kinowelt_000_bdate 2020-06-14
     2020-06-14 13:06:22   next_Kinowelt_000_btime 13:05:00
     2020-06-14 13:06:22   next_Kinowelt_000_desc Goldener Löwe, Venedig Nach 30 Jahren kehrt der kolumbianische Schriftsteller Fernando Vallejo in seine Heimatstadt Medellín zurück. Ein Ort des Schreckens erwartet ihn: die Drogenmafia und mordende Jugendliche beherrschen die einst friedliche Stadt. Inmitten von Horror, Chaos und Hass begegnet Fernando dem 16jährigen Alexis, der seinen Lebensunterhalt als Auftragskiller verdient. Eine tiefe Liebe entwickelt sich zwischen den Beiden, eine hoffnungslose Liebe, überschattet von der wachsenden Mordlust Alexis. Eines Tages wird Alexis getötet. Doch dann trifft Fernando auf Wílmar, der Alexis verblüffend ähnlich ist. Es scheint, als ob die Stadt lebende Repliken der Toten erschaffen hat. Barbet Schroeders (Die Affäre der Sunny von B., Weiblich, ledig, jung sucht...) schonungsloses Porträt einer von Drogenhandel und Bandengewalt geprägten kolumbianischen Gesellschaft
     2020-06-14 13:06:22   next_Kinowelt_000_stitle Drama
     2020-06-14 13:06:22   next_Kinowelt_000_title Die Madonna der Mörder
     2020-06-14 13:06:22   next_Kinowelt_001_bdate 2020-06-14
     2020-06-14 13:06:22   next_Kinowelt_001_btime 14:50:00
     2020-06-14 13:06:23   next_Kinowelt_001_desc David Hudson ist also sein Name! Viel mehr hat der smarte Typ nicht über seine Herkunft herausfinden können, seit er in den Hügeln von Hollywood neben einem toten Cop aufgewacht ist - ohne jegliche Erinnerung. Aber eins ist schnell klar - besonders beliebt scheint er nicht zu sein. Offenbar will ihn so ziemlich jeder um die Ecke bringen und selbst die Frauen, die bereitwillig mit ihm schlafen, sind ihm alles andere als wohl gesonnen. Und dann ist da noch dieser Privatdetektiv Sam Ruben, der ihm die ganze Zeit hinterher schnüffelt. Leichen, Drogen und schneller Sex begleiten Davids Suche nach der eigenen Identität. Er ist offensichtlich der Bad Guy in diesem Spiel. Oder etwa nicht? Der elegant gezeichnete Großstadtkrimi schwelgt in atmosphärischen Schwarzweißbildern mit akzentuierten Farbeinsätzen und untermalt seine fesselnde Story mit großartigen Jazzklängen. Spannend, brutal und sexy - ein Animationsfilm ausschließlich für Erwachsene
     2020-06-14 13:06:23   next_Kinowelt_001_stitle Animationsfilm
     2020-06-14 13:06:23   next_Kinowelt_001_title Film Noir
     2020-06-14 13:06:23   next_Kinowelt_002_bdate 2020-06-14
     2020-06-14 13:06:23   next_Kinowelt_002_btime 16:30:00
     2020-06-14 13:06:23   next_Kinowelt_002_desc 1 Silberner Bär, Berlin 1 Europäischer Filmpreis Nominiert für 2 Oscars® England in den 30er Jahren: Der hässliche und missgebildete Richard, Duke of Gloucester, will nach dem Tod seines Vaters, König Henry VI, unbedingt auf den Thron. Doch sein älterer Bruder Edward steht in der Thronfolge vor ihm und wird zum König von England gekrönt. Der machtbesessene Richard lässt daraufhin keine Intrige, keine Verschwörung oder Putschversuch aus, um seinen Bruder auszustechen. Doch als er endlich als Richard III. den Thron bestiegen hat, wenden sich seine bisherigen Verbündeten gegen ihn und sein Niedergang ist besiegelt. Regisseur Richard Loncraine verlegt die Handlung von William Shakespeares Drama Richard III. in eine Alternativrealität eines faschistischen Englands in den 1930er Jahren
     2020-06-14 13:06:23   next_Kinowelt_002_stitle Drama
     2020-06-14 13:06:23   next_Kinowelt_002_title Richard III
     2020-06-14 12:47:01   next_N24Doku_000_bdate 2020-06-14
     2020-06-14 12:47:02   next_N24Doku_000_btime 12:15:00
     2020-06-14 12:47:02   next_N24Doku_000_desc Am Flughafen München hebt ein Airbus A350 ab. Das Langstrecken-Grossraumflugzeug des europäischen Flugzeugherstellers soll seinem grössten Konkurrenten der US-amerikanischen Boeing 787 Dreamliner den Kampf ansagen. Unter allen Verkehrsflugzeugen weist der A350 den höchsten Anteil an Kohlefaserstoffen in Rumpf und Tragflächen auf und setzt somit neue Stabilitätsmassstäbe bei hohem Komfort
     2020-06-14 12:47:02   next_N24Doku_000_stitle [Dokumentation]  (2017)
     2020-06-14 12:47:02   next_N24Doku_000_title Die Super-Airliner - Flugzeuge für das neue Jahrtausend
     2020-06-14 12:47:03   next_N24Doku_001_bdate 2020-06-14
     2020-06-14 12:47:03   next_N24Doku_001_btime 13:15:00
     2020-06-14 12:47:03   next_N24Doku_001_desc Seit fast 3000 Jahren sind Hebemaschinen ein wichtiger Bestandteil der Bauindustrie. Inzwischen wurden die einst einfachen Vorrichtungen zu komplexen Konstruktionen weiterentwickelt. In dieser Sendung werden Kräne vorgestellt die in ihrer Kategorie zu den besten gehören der Brückenkran Taisun der Kroll 10.000 der Mammoet PTC200 DS der Mobilkran Liebherr LTR 11200 und die Londoner Kaikräne
     2020-06-14 12:47:03   next_N24Doku_001_stitle [Doku-Serie]  (Worlds Top 5)Riesenkräne (2013)
     2020-06-14 12:47:03   next_N24Doku_001_title Die fünf Besten
     2020-06-14 12:47:03   next_N24Doku_002_bdate 2020-06-14
     2020-06-14 12:47:03   next_N24Doku_002_btime 14:10:00
     2020-06-14 12:47:03   next_N24Doku_002_desc Seit 2017 hält Strom aus Windkraft den zweitgrössten Anteil der Energieversorgung in Deutschland - und hat damit Atom- und Kohlekraft überholt. Fast 30.000 On- und Off-Shore-Windenergieanlagen gibt es momentan in Deutschland die etwa 19 Prozent unseres Energieverbrauchs abdecken. Die Reportage verfolgt die Konstruktion eines neuen Windkraftwerks im brandenburgischen Falkenthal
     2020-06-14 12:47:03   next_N24Doku_002_stitle [Dokumentation]  (2018)
     2020-06-14 12:47:03   next_N24Doku_002_title Strom aus Sturm - Ein Windrad entsteht
     2020-06-14 12:30:34   next_NatGeoHD_000_bdate 2020-06-14
     2020-06-14 12:30:34   next_NatGeoHD_000_btime 12:25:00
     2020-06-14 12:30:34   next_NatGeoHD_000_desc Der Mars-Rover Curiosity hat Geschichte geschrieben: Seit dem 6. August 2012 ist der Mini-Roboter auf der Marsoberfläche unterwegs und sammelt wertvolle Forschungsdaten
     2020-06-14 12:30:34   next_NatGeoHD_000_stitle Astronomie
     2020-06-14 12:30:34   next_NatGeoHD_000_title Mars-Rover: Erforschung des Roten Planeten
     2020-06-14 12:30:34   next_NatGeoHD_001_bdate 2020-06-14
     2020-06-14 12:30:34   next_NatGeoHD_001_btime 13:15:00
     2020-06-14 12:30:34   next_NatGeoHD_001_desc na
     2020-06-14 12:30:34   next_NatGeoHD_001_stitle Archäologie
     2020-06-14 12:30:34   next_NatGeoHD_001_title Petra - Geheimnisse antiker Baukunst
     2020-06-14 12:30:34   next_NatGeoHD_002_bdate 2020-06-14
     2020-06-14 12:30:34   next_NatGeoHD_002_btime 14:05:00
     2020-06-14 12:30:34   next_NatGeoHD_002_desc Eine Forschungsexpedition in Jordanien fördert neue Kenntnisse zum Schatz der Könige zutage: den Minen des für seine Weisheit ebenso wie für seinen Reichtum berühmten biblischen Königs Salomon
     2020-06-14 12:30:34   next_NatGeoHD_002_stitle Dokumentation
     2020-06-14 12:30:34   next_NatGeoHD_002_title Die Suche nach den Schätzen König Salomos
     2020-06-14 13:07:51   next_PLANET_000_bdate 2020-06-14
     2020-06-14 13:07:51   next_PLANET_000_btime 12:40:00
     2020-06-14 13:07:52   next_PLANET_000_desc In Tromsø ist es spät abends und die Tourleiter sind zum letzten Mal in der Saison auf der Jagd nach dem Nordlicht. Hans-Olavs Familie packt, um am Nachmittag nach Edinburgh zu fliegen. Dort wird er seinen Whiskey vorstellen. Aber bevor er selbst packen kann, muss er einen Vortrag über Qualitätssicherung in der Tourismusbranche halten
     2020-06-14 13:07:51   next_PLANET_000_stitle Land und Leute
     2020-06-14 13:07:51   next_PLANET_000_title Magische Nächte - Auf der Suche nach dem Nordlicht: Erfolg und Abschied
     2020-06-14 13:07:52   next_PLANET_001_bdate 2020-06-14
     2020-06-14 13:07:52   next_PLANET_001_btime 13:30:00
     2020-06-14 13:07:52   next_PLANET_001_desc Zurück auf Sumatra ändert Lei Jona seinen Reisestil. Er parkt das Zebra an der Ostküste Sumatras und fliegt nach Nepal. Hier stößt er auf eine ganz andere Welt. Kathmandu, die chaotische und volle Stadt, umgeben von 8000ern. Lama Ole Nydahl, buddhistischer Lama und Tom Andreas, NLP Coach und Ethnologe schildern einfühlsam die Veränderungen und den persönlichen Gewinn durch die innere Reise
     2020-06-14 13:07:52   next_PLANET_001_stitle Tourismus
     2020-06-14 13:07:52   next_PLANET_001_title GlobalTrek - Die Kunst der inneren Reise: Teil 4
     2020-06-14 13:07:52   next_PLANET_002_bdate 2020-06-14
     2020-06-14 13:07:52   next_PLANET_002_btime 14:30:00
     2020-06-14 13:07:52   next_PLANET_002_desc Raul Gomez, der Marathon Man, liebt es zu reisen und mit den Einheimischen verschiedener Länder an lokalen Marathons teilzunehmen. Mit viel Witz begegnet er den Menschen und kommt so den Kulturen sehr nah. In dieser Folge reist er nach Kalifornien
     2020-06-14 13:07:52   next_PLANET_002_stitle Dokumentation
     2020-06-14 13:07:52   next_PLANET_002_title Marathon Man: Kalifornien L.A
     2020-06-14 1
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 13:19:07
Es fehlt eine gute Hälfte der Definition, insb die uiTable Parameter

Die Readings sind anscheinend da. Dann poste mal bitte ein "list -r" vom DOIF, ohne die "setstate" am Ende
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 13:24:17
define doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  \
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  # telnet port must not be password protected (open)\
  $_telnetPort = 7072;;\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem/';;\
  $_dataFile = $_path.'rytecDE_Basic';;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  \
  # internal variables\
  $_startTimes;;\
  \
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/["`;;'\r]//g;;\
    $text =~ s/[\n]/
/g;;\
\
    return $text;;\
  }\
  \
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub tvParse($$)\
  {\
    my ($device, $mode) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        if ((0 != $_filterChannels) ||\
            ($_->{'channel'}{'value'} =~ $_channelFilter))\
        {\
          my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
          # filter old stuff\
          if ($stop > $old)\
          {\
            if ($lastChannel ne $_->{'channel'}{'value'})\
            {\
              $lastChannel = $_->{'channel'}{'value'};;\
              $reading = $_->{'channel'}{'value'};;\
              $reading =~ s/[\.\s]//g;;\
              $reading =~ s/de$//;;\
              $n = 0;;\
              \
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
              {\
                $i = 0;;\
\
                if (0 != $_updateBasedOnStarttimes)\
                {\
                  $_startTimes{$reading} = $stop;;\
                }\
              }\
            }\
\
            if ($i < 3 && 'next' eq $mode)\
            {\
              my $fi = sprintf("%03d", $i);;\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $i++;;\
            }\
\
            if ($n < 3 && 'prime' eq $mode)\
            {\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $fmtStart = FmtDateTime($start);;\
              my $bdate = substr($fmtStart, 0, 10);;\
              my $btime = substr($fmtStart, 11, 8);;\
\
              if ($bdate.' '.$btime gt $primeTime)\
              {\
                my $fn = sprintf("%03d", $n);;\
                my $readingName;;\
                my $readingValue;;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
                $readingValue = substr(FmtDateTime($start), 0, 10);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
                $readingValue = substr(FmtDateTime($start), 11, 8);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
                if (exists($_->{'sub-title'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'sub-title'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
                if (exists($_->{'desc'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'desc'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $k++;;\
                $n++;;\
              }\
            }\
\
            if ($k >= 10)\
            {\
              `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;;\
\
              $k = 0;;\
              $sendTelnet = '';;\
            }\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
  \
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
    \
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);;\
    \
    tvMerge($_dataFile, $_path.'rytecDE_Common');;\
\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
  \
  \
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
  \
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    \
    $output = tvDownloadMerge();;\
    \
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
  \
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
  \
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
  \
  sub DOIF::doParse($)\
  {\
    my ($name, $mode) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
  \
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
        \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 5, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
  \
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:15]) \
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST room 1_test
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE=1;;\
\
  $TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{1..6} = "border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub rgUnfold\
  {\
    my ($title, $desc) = @_;;\
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
\
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1
/g;;\
    $desc =~ s/
/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1
/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/
/g;;\
    return "".$title."";;\
  }\
}\
\
DEF TPL_TV(ICON("tv/$4")|substr([$1:$2_$3_000_btime],0,5)|rgUnfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|rgUnfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|rgUnfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,ARD,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,Pro7,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,Kabel,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
" ;"|" ;"|" ;"|" ;"|" ;"|" ;"|" ;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,ARD,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,Pro7,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,Kabel,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 13:27:17
Ok, sieht gut aus. Dann fehlt nur noch das Ergebnis von
ls -la /opt/fhem/www/images/tv

bzw unter windoof:
dir <path-to-fhem>\www\images\tv
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 13:29:18
Noch mal, das gab es nicht. Jetzt sind die Logos von Avm drin.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 13:30:48
Und die haben wahrscheinlich falsche Dateinamen. Oder das Format stimmt nicht.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 13:37:01
DEF TPL_TV(ICON("tv/$4")|s
Das heisst, im Verzeichnis tv müssen die Logos von den Kanäle stehen. Dass Du die aus AVM kopiert hast, sollte kein Pb sein. Die müssen nur die Namen wie im DOIF haben:
ZitatTPL_TV($SELF,next,ARD,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,Pro7,pro7)\

also z.B. ard.png, zdf.png, sat1.png usw

Quelle: https://download.avm.de/tv/logos/

EDIT: und die müssen natürlich die richtige Berechtigungen habe. Deswegen bitte das Ergebnis von
ls -la /opt/fhem/www/images/tv, was Du, warum auch immer, noch nicht geliefert hast. Ohne das, kann man nicht weiter analysieren.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 13:44:20
Hab noch nicht alle umbenannt, aber es werden gar keine angezeigt.

Zitatpi@fhem3:~ $ sudo ls -la /opt/fhem/www/images/tv
insgesamt 1176
drwxrwxrwx 2 fhem dialout  4096 Jun 14 13:22 .
drwxrwxrwx 8 fhem dialout  4096 Jun 14 13:21 ..
-rwxrwxrwx 1 fhem dialout  9261 Jun 14 11:38 3sat_hd.png
-rwxrwxrwx 1 fhem dialout 10139 Jun 14 11:35 3sat.png
-rwxrwxrwx 1 fhem dialout  8201 Jun 14 11:38 alex.png
-rwxrwxrwx 1 fhem dialout 23520 Jun 14 11:38 aljazeera.png
-rwxrwxrwx 1 fhem dialout  9897 Jun 14 11:38 anixe_hd.png
-rwxrwxrwx 1 fhem dialout  6885 Jun 14 11:38 anixe_sd.png
-rwxrwxrwx 1 fhem dialout 15500 Jun 14 11:38 ard_alpha.png
-rwxrwxrwx 1 fhem dialout  4004 Jun 14 11:39 ard_one_hd.png
-rwxrwxrwx 1 fhem dialout  8178 Jun 14 11:39 arte_hd.png
-rwxrwxrwx 1 fhem dialout  6532 Jun 14 11:39 arte.png
-rwxrwxrwx 1 fhem dialout  9444 Jun 14 11:39 astro_tv.png
-rwxrwxrwx 1 fhem dialout 13555 Jun 14 11:39 bbc_world.png
-rwxrwxrwx 1 fhem dialout  9922 Jun 14 11:39 bibel_tv.png
-rwxrwxrwx 1 fhem dialout 12284 Jun 14 11:39 bloomberg.png
-rwxrwxrwx 1 fhem dialout     0 Jun 14 11:39 br_alpha.png
-rwxrwxrwx 1 fhem dialout 10252 Jun 14 11:39 br_hd.png
-rwxrwxrwx 1 fhem dialout 12603 Jun 14 11:39 br.png
-rwxrwxrwx 1 fhem dialout 16714 Jun 14 11:39 channel21.png
-rwxrwxrwx 1 fhem dialout 10721 Jun 14 11:40 cnn.png
-rwxrwxrwx 1 fhem dialout  8865 Jun 14 11:40 das_erste_hd.png
-rwxrwxrwx 1 fhem dialout  9660 Jun 14 11:40 das_erste.png
-rwxrwxrwx 1 fhem dialout 18260 Jun 14 11:40 das_vierte.png
-rwxrwxrwx 1 fhem dialout  7063 Jun 14 12:44 deutsche_welle.png
-rwxrwxrwx 1 fhem dialout 52861 Jun 14 12:44 disney_channel.png
-rwxrwxrwx 1 fhem dialout  6815 Jun 14 12:44 dmax.png
-rwxrwxrwx 1 fhem dialout 24451 Jun 14 12:44 dmf.png
-rwxrwxrwx 1 fhem dialout  6224 Jun 14 12:45 einsfestival_hd.png
-rwxrwxrwx 1 fhem dialout     0 Jun 14 12:45 eins_festival.png
-rwxrwxrwx 1 fhem dialout  8724 Jun 14 12:44 einsPlus_hd.png
-rwxrwxrwx 1 fhem dialout  9790 Jun 14 12:45 eins_plus.png
-rwxrwxrwx 1 fhem dialout  4228 Jun 14 12:46 einszweidrei_tv.png
-rwxrwxrwx 1 fhem dialout 48120 Jun 14 12:46 erf.png
-rwxrwxrwx 1 fhem dialout  6360 Jun 14 12:46 euronews.png
-rwxrwxrwx 1 fhem dialout     0 Jun 14 12:46 eurosport.png
-rwxrwxrwx 1 fhem dialout  6054 Jun 14 12:46 hr_hd.png
-rwxrwxrwx 1 fhem dialout  9043 Jun 14 12:46 hr.png
-rwxrwxrwx 1 fhem dialout  4563 Jun 14 12:46 hse24_extra.png
-rwxrwxrwx 1 fhem dialout  7724 Jun 14 12:46 hse24.png
-rwxrwxrwx 1 fhem dialout  2881 Jun 14 12:47 joiz.png
-rwxrwxrwx 1 fhem dialout 32035 Jun 14 12:47 juwelo.png
-rwxrwxrwx 1 fhem dialout 11593 Jun 14 12:47 kabel1_doku.png
-rwxrwxrwx 1 fhem dialout 11041 Jun 14 12:47 kabel1.png
-rwxrwxrwx 1 fhem dialout 26057 Jun 14 12:47 kabel_deutschland.png
-rwxrwxrwx 1 fhem dialout 14311 Jun 14 12:47 kika_hd.png
-rwxrwxrwx 1 fhem dialout  9024 Jun 14 12:47 kika.png
-rwxrwxrwx 1 fhem dialout  6856 Jun 14 12:47 mdr_hd.png
-rwxrwxrwx 1 fhem dialout  3980 Jun 14 12:47 mdr.png
-rwxrwxrwx 1 fhem dialout  5822 Jun 14 12:47 n24.png
-rwxrwxrwx 1 fhem dialout  9225 Jun 14 12:47 ndr_hd.png
-rwxrwxrwx 1 fhem dialout  9046 Jun 14 12:47 ndr.png
-rwxrwxrwx 1 fhem dialout  8828 Jun 14 12:48 nickelodeon.png
-rwxrwxrwx 1 fhem dialout 10189 Jun 14 12:48 nitro.png
-rwxrwxrwx 1 fhem dialout     0 Jun 14 12:48 ntv.png
-rwxrwxrwx 1 fhem dialout  4764 Jun 14 12:48 one_tv.png
-rwxrwxrwx 1 fhem dialout 16325 Jun 14 12:48 parlament.png
-rwxrwxrwx 1 fhem dialout  9056 Jun 14 12:48 phoenix_hd.png
-rwxrwxrwx 1 fhem dialout  5157 Jun 14 12:48 phoenix.png
-rwxrwxrwx 1 fhem dialout  4919 Jun 14 12:48 pro7maxx.png
-rwxrwxrwx 1 fhem dialout  4628 Jun 14 12:48 pro7.png
-rwxrwxrwx 1 fhem dialout  6863 Jun 14 12:49 qvc_plus.png
-rwxrwxrwx 1 fhem dialout 14339 Jun 14 12:49 qvc.png
-rwxrwxrwx 1 fhem dialout  6998 Jun 14 12:49 radio_bremen.png
-rwxrwxrwx 1 fhem dialout  9208 Jun 14 12:49 rbb_hd.png
-rwxrwxrwx 1 fhem dialout  3658 Jun 14 12:49 rbb.png
-rwxrwxrwx 1 fhem dialout 11041 Jun 14 12:49 rtl2.png
-rwxrwxrwx 1 fhem dialout  8122 Jun 14 12:49 rtlnitro.png
-rwxrwxrwx 1 fhem dialout  7271 Jun 14 12:49 rtlplus.png
-rwxrwxrwx 1 fhem dialout  8489 Jun 14 12:49 rtl.png
-rwxrwxrwx 1 fhem dialout     0 Jun 14 12:49 sat1gold.png
-rwxrwxrwx 1 fhem dialout 39089 Jun 14 12:49 sat1.png
-rwxrwxrwx 1 fhem dialout  2455 Jun 14 12:49 servus.png
-rwxrwxrwx 1 fhem dialout  7863 Jun 14 12:50 servus_tv.png
-rwxrwxrwx 1 fhem dialout 10620 Jun 14 12:50 sixx.png
-rwxrwxrwx 1 fhem dialout  4212 Jun 14 12:50 skyselect.png
-rwxrwxrwx 1 fhem dialout  6780 Jun 14 12:50 sonlife.png
-rwxrwxrwx 1 fhem dialout  6146 Jun 14 12:50 sonnenklar.png
-rwxrwxrwx 1 fhem dialout 10131 Jun 14 12:50 sport1.png
-rwxrwxrwx 1 fhem dialout 17073 Jun 14 12:50 sr_hd.png
-rwxrwxrwx 1 fhem dialout  9688 Jun 14 12:50 sr.png
-rwxrwxrwx 1 fhem dialout  7311 Jun 14 12:50 superrtl.png
-rwxrwxrwx 1 fhem dialout  5917 Jun 14 12:50 swr_hd.png
-rwxrwxrwx 1 fhem dialout  5666 Jun 14 12:50 swr.png
-rwxrwxrwx 1 fhem dialout  9382 Jun 14 12:50 tagesschau24_hd.png
-rwxrwxrwx 1 fhem dialout  5382 Jun 14 12:50 tagesschau24.png
-rwxrwxrwx 1 fhem dialout  8560 Jun 14 12:51 tele5.png
-rwxrwxrwx 1 fhem dialout  7797 Jun 14 12:51 tlc.png
-rwxrwxrwx 1 fhem dialout 35165 Jun 14 12:51 toggo_plus.png
-rwxrwxrwx 1 fhem dialout  6482 Jun 14 12:51 tv5_monde.png
-rwxrwxrwx 1 fhem dialout  4800 Jun 14 12:51 viva.png
-rwxrwxrwx 1 fhem dialout 16688 Jun 14 12:51 vox.png
-rwxrwxrwx 1 fhem dialout  8817 Jun 14 12:51 wdr_hd.png
-rwxrwxrwx 1 fhem dialout  9893 Jun 14 12:51 wdr.png
-rwxrwxrwx 1 fhem dialout  3798 Jun 14 12:52 zdf_hd.png
-rwxrwxrwx 1 fhem dialout  7159 Jun 14 12:52 zdf_info_hd.png
-rwxrwxrwx 1 fhem dialout  3339 Jun 14 12:52 zdf_info.png
-rwxrwxrwx 1 fhem dialout  6316 Jun 14 12:53 zdf_kultur_hd.png
-rwxrwxrwx 1 fhem dialout  2886 Jun 14 12:52 zdf_kultur.png
-rwxrwxrwx 1 fhem dialout  7280 Jun 14 12:53 zdf_neo_hd.png
-rwxrwxrwx 1 fhem dialout  3011 Jun 14 12:53 zdf_neo.png
-rwxrwxrwx 1 fhem dialout  7723 Jun 14 12:51 zdf.png
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 13:55:27
Kann ich jetzt gerade nicht, da im Moment nicht am Rechner.
Aber ich kann dir versichern dass die Dateinamen zum Beispiel pro7 stimmen und auch der owner und Gruppe.

Die Frage ist doch eher wo die Anfang herkommen sollen,wenn
man sie nicht manuell kopiert.

Oder sag uns doch einfach mal wo du sie her hast und ob du du sie auch manuell kopiert hast.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 14:32:13
Heir noch mal ls -la /opt/fhem/www/images/tv:

drwxr-xr-x  3 fhem dialout  4096 Jun 14 10:55 .
drwxrwxrwx 17 fhem dialout  4096 Jun 14 10:54 ..
-rw-r--r--  1 fhem dialout  9261 Aug 15  2017 3sat_hd.png
-rw-r--r--  1 fhem dialout 10139 Aug 15  2017 3sat.png
-rw-r--r--  1 fhem dialout  8201 Aug 15  2017 alex.png
-rw-r--r--  1 fhem dialout 23520 Aug 15  2017 aljazeera.png
-rw-r--r--  1 fhem dialout  9897 Aug 15  2017 anixe_hd.png
-rw-r--r--  1 fhem dialout  6885 Aug 15  2017 anixe_sd.png
-rw-r--r--  1 fhem dialout 15500 Aug 15  2017 ard_alpha.png
-rw-r--r--  1 fhem dialout  4004 Aug 15  2017 ard_one_hd.png
-rw-r--r--  1 fhem dialout  8178 Aug 15  2017 arte_hd.png
-rw-r--r--  1 fhem dialout  6532 Aug 15  2017 arte.png
-rw-r--r--  1 fhem dialout  9444 Aug 15  2017 astro_tv.png
-rw-r--r--  1 fhem dialout 13555 Aug 15  2017 bbc_world.png
-rw-r--r--  1 fhem dialout  9922 Aug 15  2017 bibel_tv.png
-rw-r--r--  1 fhem dialout 12284 Aug 15  2017 bloomberg.png
-rw-r--r--  1 fhem dialout  4833 Aug 15  2017 br_alpha.png
-rw-r--r--  1 fhem dialout 10252 Aug 15  2017 br_hd.png
-rw-r--r--  1 fhem dialout 12603 Aug 15  2017 br.png
-rw-r--r--  1 fhem dialout 16714 Aug 15  2017 channel21.png
-rw-r--r--  1 fhem dialout 10721 Aug 15  2017 cnn.png
-rw-r--r--  1 fhem dialout  8865 Aug 15  2017 das_erste_hd.png
-rw-r--r--  1 fhem dialout  9660 Aug 15  2017 das_erste.png
-rw-r--r--  1 fhem dialout 18260 Aug 15  2017 das_vierte.png
-rw-r--r--  1 fhem dialout  7063 Aug 15  2017 deutsche_welle.png
-rw-r--r--  1 fhem dialout 52861 Aug 15  2017 disney_channel.png
-rw-r--r--  1 fhem dialout  6815 Aug 15  2017 dmax.png
-rw-r--r--  1 fhem dialout 24451 Aug 15  2017 dmf.png
-rw-r--r--  1 fhem dialout  6224 Aug 15  2017 einsfestival_hd.png
-rw-r--r--  1 fhem dialout  5045 Aug 15  2017 eins_festival.png
-rw-r--r--  1 fhem dialout  8724 Aug 15  2017 einsPlus_hd.png
-rw-r--r--  1 fhem dialout  9790 Aug 15  2017 eins_plus.png
-rw-r--r--  1 fhem dialout  4228 Aug 15  2017 einszweidrei_tv.png
-rw-r--r--  1 fhem dialout 48120 Aug 15  2017 erf.png
-rw-r--r--  1 fhem dialout  6360 Aug 15  2017 euronews.png
-rw-r--r--  1 fhem dialout 22771 Aug 15  2017 eurosport.png
-rw-r--r--  1 fhem dialout   272 Aug 15  2017 filelist.txt
-rw-r--r--  1 fhem dialout  6054 Aug 15  2017 hr_hd.png
-rw-r--r--  1 fhem dialout  9043 Aug 15  2017 hr.png
-rw-r--r--  1 fhem dialout  4563 Aug 15  2017 hse24_extra.png
-rw-r--r--  1 fhem dialout  7724 Aug 15  2017 hse24.png
-rw-r--r--  1 fhem dialout  2881 Aug 15  2017 joiz.png
-rw-r--r--  1 fhem dialout 32035 Aug 15  2017 juwelo.png
-rw-r--r--  1 fhem dialout 11593 Aug 15  2017 kabel1_doku.png
-rw-r--r--  1 fhem dialout 11041 Aug 15  2017 kabel1.png
-rw-r--r--  1 fhem dialout 26057 Aug 15  2017 kabel_deutschland.png
-rw-r--r--  1 fhem dialout 14311 Aug 15  2017 kika_hd.png
-rw-r--r--  1 fhem dialout  9024 Aug 15  2017 kika.png
drwxr-xr-x  2 fhem dialout  4096 Jun 14 10:53 logos
-rw-r--r--  1 fhem dialout  6856 Aug 15  2017 mdr_hd.png
-rw-r--r--  1 fhem dialout  3980 Aug 15  2017 mdr.png
-rw-r--r--  1 fhem dialout  5822 Aug 15  2017 n24.png
-rw-r--r--  1 fhem dialout  9225 Aug 15  2017 ndr_hd.png
-rw-r--r--  1 fhem dialout  9046 Aug 15  2017 ndr.png
-rw-r--r--  1 fhem dialout  8828 Aug 15  2017 nickelodeon.png
-rw-r--r--  1 fhem dialout 10189 Aug 15  2017 nitro.png
-rw-r--r--  1 fhem dialout 17126 Aug 15  2017 ntv.png
-rw-r--r--  1 fhem dialout  4764 Aug 15  2017 one_tv.png
-rw-r--r--  1 fhem dialout 16325 Aug 15  2017 parlament.png
-rw-r--r--  1 fhem dialout  9056 Aug 15  2017 phoenix_hd.png
-rw-r--r--  1 fhem dialout  5157 Aug 15  2017 phoenix.png
-rw-r--r--  1 fhem dialout  4919 Aug 15  2017 pro7maxx.png
-rw-r--r--  1 fhem dialout  4628 Aug 15  2017 pro7.png
-rw-r--r--  1 fhem dialout  6863 Aug 15  2017 qvc_plus.png
-rw-r--r--  1 fhem dialout 14339 Aug 15  2017 qvc.png
-rw-r--r--  1 fhem dialout  6998 Aug 15  2017 radio_bremen.png
-rw-r--r--  1 fhem dialout  9208 Aug 15  2017 rbb_hd.png
-rw-r--r--  1 fhem dialout  3658 Aug 15  2017 rbb.png
-rw-r--r--  1 fhem dialout 11041 Aug 15  2017 rtl2.png
-rw-r--r--  1 fhem dialout  8122 Aug 15  2017 rtlnitro.png
-rw-r--r--  1 fhem dialout  7271 Aug 15  2017 rtlplus.png
-rw-r--r--  1 fhem dialout  8489 Aug 15  2017 rtl.png
-rw-r--r--  1 fhem dialout 11658 Aug 15  2017 sat1gold.png
-rw-r--r--  1 fhem dialout 39089 Aug 15  2017 sat1.png
-rw-r--r--  1 fhem dialout  2455 Aug 15  2017 servus.png
-rw-r--r--  1 fhem dialout  7863 Aug 15  2017 servus_tv.png
-rw-r--r--  1 fhem dialout 10620 Aug 15  2017 sixx.png
-rw-r--r--  1 fhem dialout  4212 Aug 15  2017 skyselect.png
-rw-r--r--  1 fhem dialout  6780 Aug 15  2017 sonlife.png
-rw-r--r--  1 fhem dialout  6146 Aug 15  2017 sonnenklar.png
-rw-r--r--  1 fhem dialout 10131 Aug 15  2017 sport1.png
-rw-r--r--  1 fhem dialout 17073 Aug 15  2017 sr_hd.png
-rw-r--r--  1 fhem dialout  9688 Aug 15  2017 sr.png
-rw-r--r--  1 fhem dialout  7311 Aug 15  2017 superrtl.png
-rw-r--r--  1 fhem dialout  5917 Aug 15  2017 swr_hd.png
-rw-r--r--  1 fhem dialout  5666 Aug 15  2017 swr.png
-rw-r--r--  1 fhem dialout  9382 Aug 15  2017 tagesschau24_hd.png
-rw-r--r--  1 fhem dialout  5382 Aug 15  2017 tagesschau24.png
-rw-r--r--  1 fhem dialout  8560 Aug 15  2017 tele5.png
-rw-r--r--  1 fhem dialout  7797 Aug 15  2017 tlc.png
-rw-r--r--  1 fhem dialout 35165 Aug 16  2017 toggo_plus.png
-rw-r--r--  1 fhem dialout  6482 Aug 15  2017 tv5_monde.png
-rw-r--r--  1 fhem dialout  4800 Aug 15  2017 viva.png
-rw-r--r--  1 fhem dialout 16688 Aug 15  2017 vox.png
-rw-r--r--  1 fhem dialout  8817 Aug 15  2017 wdr_hd.png
-rw-r--r--  1 fhem dialout  9893 Aug 15  2017 wdr.png
-rw-r--r--  1 fhem dialout  3798 Aug 15  2017 zdf_hd.png
-rw-r--r--  1 fhem dialout  7159 Aug 15  2017 zdf_info_hd.png
-rw-r--r--  1 fhem dialout  3339 Aug 15  2017 zdf_info.png
-rw-r--r--  1 fhem dialout  6316 Aug 15  2017 zdf_kultur_hd.png
-rw-r--r--  1 fhem dialout  2886 Aug 15  2017 zdf_kultur.png
-rw-r--r--  1 fhem dialout  7280 Aug 15  2017 zdf_neo_hd.png
-rw-r--r--  1 fhem dialout  3011 Aug 15  2017 zdf_neo.png
-rw-r--r--  1 fhem dialout  7723 Aug 15  2017 zdf.png


Bei mir ist sogar das tv verzeichnis noch im iconPath meiner web instanz.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 14 Juni 2020, 17:43:12
Die Icons habe ich nicht mit abgelegt, die muss sich jeder selbst kopieren. Der Pfad ist ja inzwischen bekannt und die Rechte müssen richtig gesetzt sein. Wenn das alles passiert ist, muss fhem neu gestartet werden, sonst werden die Icons nicht geladen. Es muss auch darauf geachtet werden, dass die Bilder die richtigen Namen haben. Die sehr ihr direkt im doif als Text, wenn noch kein entsprechendes Bild hinterlegt wurde.

Wenn es euch zu lange dauert bis etwas passiert, kann folgendes gemacht werden:

set doif_TEST cmd_2

set doif_TEST cmd_3
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 17:57:07
So jetzt habe ich das Problem gelöst.
Wenn man den tv ordner nach /opt/fhem/images/default kopiert dann funktionierts mit der Anzeige der Logos.
Also noch mal genau im folder:

/opt/fhem/images/default/tv

müssen die logos liegen.
Zumindest funktionierts bei mir so.


Gruß

Carlos
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 18:29:07
Bei mir /opt/fhem/www/images/default/tv
Aber läuft nun auch.
Vielen Dank für die Hilfe.

Nochmal kurz zu meiner Zusatzfrage von vorhin:
Wo finde ich die Namen der TV-Sender, z.B. für Tele 5?
Kann ja tele5, TELE5, Tele_5 usw. sein.

Bin dankbar für einen Tipp.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: carlos am 14 Juni 2020, 18:41:26
Sorry, natürlich www muss noch mit dazu.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 19:18:33
Zitat von: Invers am 14 Juni 2020, 18:29:07
Nochmal kurz zu meiner Zusatzfrage von vorhin:
Wo finde ich die Namen der TV-Sender, z.B. für Tele 5?
Kann ja tele5, TELE5, Tele_5 usw. sein.

Bin dankbar für einen Tipp.
Diese Frage habe ich hier bereits geantwortet: https://forum.fhem.de/index.php/topic,112081.msg1064249.html#msg1064249
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 19:25:11
Sorry, habe ich übersehen. Danke.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 19:58:01
Ich muss doch nochmal nerven:
Wenn ich Sender im Attribut UITable lösche, verschiebt sich die Liste der Sender.
Wo ist denn die Anzahl der Tabellenzeilen hinterlegt?
Ich möchte Sender entfernen und hinzufügen.
Ich finde die entsprechende Stelle nicht.

Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 20:05:13
Du hast einmal ein Filter:
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\


und dann 2 uiTables Einträge pro Kanal:

"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,ARD,ard)\
(...)
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,ARD,ard)\
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 14 Juni 2020, 20:08:10
Das hatte ich beides schon gefunden, aber nur im Attribut die Sender gelöscht, die ich nicht wollte.
Ich werde sie nun auch im Filter löschen.
Ich danke dir.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 14 Juni 2020, 20:44:24
Das mit dem korrigierten Logo-Pfad passt schon  und das funktioniert jetzt :-)

Ich finde in meinem Verzeichnis /opt/fhem auch die Dateien rytecDE_Basic und rytecDE_Common, doch leider bleiben bei mir alle Spalten der Programmtabelle leer. Offenbar werden die erfolgreich heruntergeladenen Daten nicht verarbeitet.

Gehe ich in das DOIF, wird offenbar doch ein blocking call ausgelöst, der mir das Web-Interface so blockiert, dass ich booten muss, um wieder ranzukommen (Fhem läuft und die Systemlast ist auch passabel). Aber ein Modul meiner 1-Wire Sensoren wird blockiert (OWX_SER), was sämtliche Steuerungsprozesse hängen lässt, es werden hundertfach diese Zeilen erzeugt:
2020.06.14 18:54:53 1: OWX_SER::Query OWio1:  0 of 1 bytes in last attempt and state opened, this is an unrecoverable error

und beim Abbrechen gibt es diese Zeile im Log:
2020.06.14 18:54:56 1: Timeout for DOIF::doParse reached, terminated process 1245
2020.06.14 18:54:56 1: doif_TEST: Blocking call aborted (parse).


Im Betrieb gibt es häufiger diese Fehler im Log:
an't locate object method "strptime" via package "Time::Piece" (perhaps you forgot to load "Time::Piece"?) at (eval 163) line 36.
2020.06.14 19:11:51 1: doif_TEST: Blocking call aborted (parse).
2020.06.14 19:11:51 2: DbLog logdb -> DbLog_PushAsync Process died prematurely

und auch:
2020.06.14 19:12:51 1: FRITZBOX Fritzbox: Readout_Aborted.1931 Error: Timeout when reading Fritz!Box data.

2020.06.14 19:16:45 1: Timeout for DOIF::doParse reached, terminated process 1275
2020.06.14 19:16:45 1: doif_TEST: Blocking call aborted (parse).

2020.06.14 19:58:56 1: Timeout for SYSMON_blockingCall reached, terminated process 1517

Alles Fehler, die ohne das DOIF nicht existier(t)en.

Auch nach dem Hinzufügen des Package Time::Piece auf dem Console des Linux-Systems (cpan install Time::Piece) verschwanden diese Fehler nicht und:  Immer noch leere Spalten.

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 14 Juni 2020, 20:59:45
Also... BlockingCall, wie ihr Name es nicht sagt, ist eine Funktion, die eigentlich non-blocking Calls macht, durch ein Fork des Haupt Fhem Prozess.

Hast Du vielleicht das Attribut "blockingCallMax" auf global gesetzt? (bzw. ist dein Fhem Rechner ein Windows Rechner?)

Relevant wäre ein "ps aux |grep perl" aus einem Terminal, wenn Fhem hängt
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 14 Juni 2020, 21:15:02
Hast du nach der Installation von Time::Piece den Rechner mal rebootet? Ich könnte die Verwendung der Bibliothek aber auch vermeiden, das wäre dann langsamer aber kompatibler.

PS: Im ersten Beitrag habe ich das DOIF noch mal geändert, so das man Time::Piece nicht mehr braucht. Man kann es aber manuell in der Funktion xmltv2epoch einschalten, wenn man es möchte.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 14 Juni 2020, 22:36:52
Zitat von: amenomade am 14 Juni 2020, 20:59:45
Hast Du vielleicht das Attribut "blockingCallMax" auf global gesetzt? (bzw. ist dein Fhem Rechner ein Windows Rechner?)

Relevant wäre ein "ps aux |grep perl" aus einem Terminal, wenn Fhem hängt

Also: Es ist ein PI und das Attribut ist nicht gesetzt.
Dem anderen Hinweis werde ich nachgehen, aber erst morgen...

Danke für die Hinweise

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 14 Juni 2020, 22:38:21
Zitat von: mumpitzstuff am 14 Juni 2020, 21:15:02
Hast du nach der Installation von Time::Piece den Rechner mal rebootet? Ich könnte die Verwendung der Bibliothek aber auch vermeiden, das wäre dann langsamer aber kompatibler.

Ja, ich habe (notgedrungen sogar mehrfach) neu gebootet. Die Fehlerhinweise in dieser Richtung sind nun ja auch weg. Lediglich die BlockingCall-Hinweise und vor allem der Ärger mit OWX_SER verleidet mir aktuell die Freude...

Herzliche Grüße

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juni 2020, 08:05:26
Ich habe mal 3sat hinzugefügt. Das hat auch geklappt, es wird alles richtig angezeigt.
Nur die 2. Überschrift (also bei prime) wird nicht mehr gelb gefärbt. Ich sehe nicht, was ich da falsch gemacht habe.
Kannst du mir einen Tipp geben?

Besten Dank im Voraus.

[code]defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  \
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|3sat\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  # telnet port must not be password protected (open)\
  $_telnetPort = 7072;;\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem/';;\
  $_dataFile = $_path.'rytecDE_Basic';;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  \
  # internal variables\
  $_startTimes;;\
  \
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/["`;;'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
  \
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub tvParse($$)\
  {\
    my ($device, $mode) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        if ((0 != $_filterChannels) ||\
            ($_->{'channel'}{'value'} =~ $_channelFilter))\
        {\
          my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
          # filter old stuff\
          if ($stop > $old)\
          {\
            if ($lastChannel ne $_->{'channel'}{'value'})\
            {\
              $lastChannel = $_->{'channel'}{'value'};;\
              $reading = $_->{'channel'}{'value'};;\
              $reading =~ s/[\.\s]//g;;\
              $reading =~ s/de$//;;\
              $n = 0;;\
              \
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
              {\
                $i = 0;;\
\
                if (0 != $_updateBasedOnStarttimes)\
                {\
                  $_startTimes{$reading} = $stop;;\
                }\
              }\
            }\
\
            if ($i < 3 && 'next' eq $mode)\
            {\
              my $fi = sprintf("%03d", $i);;\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $i++;;\
            }\
\
            if ($n < 3 && 'prime' eq $mode)\
            {\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $fmtStart = FmtDateTime($start);;\
              my $bdate = substr($fmtStart, 0, 10);;\
              my $btime = substr($fmtStart, 11, 8);;\
\
              if ($bdate.' '.$btime gt $primeTime)\
              {\
                my $fn = sprintf("%03d", $n);;\
                my $readingName;;\
                my $readingValue;;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
                $readingValue = substr(FmtDateTime($start), 0, 10);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
                $readingValue = substr(FmtDateTime($start), 11, 8);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
                if (exists($_->{'sub-title'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'sub-title'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
                if (exists($_->{'desc'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'desc'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $k++;;\
                $n++;;\
              }\
            }\
\
            if ($k >= 10)\
            {\
              `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;;\
\
              $k = 0;;\
              $sendTelnet = '';;\
            }\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        `perl /opt/fhem/fhem.pl $_telnetPort "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
  \
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
    \
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);;\
    \
    tvMerge($_dataFile, $_path.'rytecDE_Common');;\
\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
  \
  \
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
  \
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    \
    $output = tvDownloadMerge();;\
    \
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
  \
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
  \
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
  \
  sub DOIF::doParse($)\
  {\
    my ($name, $mode) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
  \
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
        \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 5, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
  \
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:15]) \
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST room TEST
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE=1;;\
\
  $TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{1..6} = "border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub rgUnfold\
  {\
    my ($title, $desc) = @_;;\
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
\
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
    return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";;\
  }\
}\
\
DEF TPL_TV(ICON("tv/$4")|substr([$1:$2_$3_000_btime],0,5)|rgUnfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|rgUnfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|rgUnfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,3sat,3SAT)\
TPL_TV($SELF,next,ARD,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,Pro7,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,Kabel,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,3sat,3SAT)\
TPL_TV($SELF,prime,ARD,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,Pro7,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,Kabel,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)\


setstate doif_TEST cmd_2
setstate doif_TEST 2020-06-15 07:40:32 block_02 executed
setstate doif_TEST 2020-06-15 07:52:17 block_init executed
setstate doif_TEST 2020-06-14 20:28:50 cmd 2
setstate doif_TEST 2020-06-14 20:28:50 cmd_event set_cmd_2
setstate doif_TEST 2020-06-14 20:28:50 cmd_nr 2
setstate doif_TEST 2020-06-14 20:25:32 mode enabled
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_000_btime 07:15:00
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_000_desc In Johannesburg sind die amerikanischen Brüder Timothy und Brandon verschwunden die in den Semesterferien in der Bar ihrer Tante gearbeitet hatten. Timothy wird tot und nach einem Brauch der Zulu verstümmelt aufgefunden. Kurz zuvor war es schon einer jungen Frau genauso ergangen. Dem IRT wird eine Spezialeinheit der südafrikanischen Armee und die Profilerin Doshi zur Seite gestellt.<br>Laura Belsey<br>Gary Sinise<br>Alana De La Garza<br>Daniel Henney<br>Tyler James Williams<br>Annie Funke<br>Arnold Vosloo<br>Mykelti Williamson<br>Bahni Turpin<br>Cliff Simon<br>Brenda Bakke<br>Dayo Ade<br>Austin M. James<br>Musetta Vander<br>Sean Michael<br>Skyler Seymour<br>Garikayi Mutambirwa<br>Jacqueline Jandrell<br>Mike Falkow<br>Kegn Matungulu
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_000_stitle Mord verjährt nicht (2016) [16+]
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_000_title Criminal Minds: Beyond Borders
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_001_btime 08:00:00
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_001_desc Kristin erlitt eine Fehlgeburt und wurde von ihrem Mann verlassen. Trotz dieser traumatischen Erlebnisse werden sie und ihre beste Freundin Ashley fast gleichzeitig schwanger. Eine Woche nach der Geburt ihres Kindes stirbt Ashley bei einem Autounfall das Neugeborene bleibt unauffindbar. Als auch Kristin verschwindet befürchtet Ashleys Mann Brian dass Kristin hinter Ashleys Tod steckt.<br>Michael Feifer<br>Kaitlyn Black<br>David Gallagher<br>Vanessa Evigan<br>Alexandra Paul<br>Mark Famiglietti<br>Caia Coley<br>Betsy Russell<br>Ardeshir Radpour<br>Emily Branum<br>Mark Hapka<br>Samm Enman<br>Camille Balsamo<br>Shawn Tira<br>Sharon M. Bell<br>Duke Van Patten<br>Penny Dill<br>Siena Milian<br>Maverick Murray Adcox<br>Marc Abbink
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_001_stitle (Born and Missing) (2017) [12+]
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_001_title Das Baby meiner toten Freundin
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_002_btime 09:35:00
setstate doif_TEST 2020-06-15 07:40:43 next_13thStreet_002_desc Ein allseits beliebter Hausmeister wird erschossen. Es gibt keine sichtbaren Beweise und kein Motiv. Die einzige Besonderheit an dem Fall ist dass der Mörder handgefertigte Kugeln benutzte die Quecksilber enthalten. Die Polizisten müssen bei diesem Fall die Hilfe eines in die Jahre gekommenen Gauners in Anspruch nehmen.<br>Christopher Misiano<br>Jerry Orbach<br>Benjamin Bratt<br>Sam Waterston<br>Steven Hill<br>S. Epatha Merkerson<br>Mark Bateman<br>Carey Lowell<br>John Bedford Lloyd<br>Tom ORourke<br>Richard Hamilton<br>E. Katherine Kerr<br>Dan Ziskie<br>Jennifer Van Dyck<br>Vivienne Benesch<br>Randle Mell<br>Victor Anthony<br>Larry Attile<br>D.C. Benny<br>Susan Blommaert
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_002_stitle Leitfaden für Attentäter (1996) [18+]
setstate doif_TEST 2020-06-15 07:40:42 next_13thStreet_002_title Law &amp Order
setstate doif_TEST 2020-06-15 07:40:32 next_3sat_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:32 next_3sat_000_btime 07:30:00
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_000_desc Alpenpanorama zeigt über zahlreiche Web- und Panoramakameras täglich Livebilder aus ausgewählten Urlaubsorten.Die Sendung informiert auch über Temperatur- und Wetterbedingungen vor Ort
setstate doif_TEST 2020-06-15 07:40:32 next_3sat_000_stitle Kamerafahrt
setstate doif_TEST 2020-06-15 07:40:32 next_3sat_000_title Alpenpanorama
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_001_btime 08:00:00
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_001_desc Die Früh-ZIB informiert von Montag bis Freitag über das aktuelle Geschehen aus Innen- und Außenpolitik, Wirtschaft, Wissenschaft, Kultur und Chronik.Reportagen und Hintergrundberichte vertiefen das Verständnis der aktuellen Ereignisse
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_001_stitle Nachrichten
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_001_title ZIB
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_002_btime 08:05:00
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_002_desc Alpenpanorama zeigt über zahlreiche Web- und Panoramakameras täglich Livebilder aus ausgewählten Urlaubsorten.Die Sendung informiert auch über Temperatur- und Wetterbedingungen vor Ort
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_002_stitle Kamerafahrt
setstate doif_TEST 2020-06-15 07:40:33 next_3sat_002_title Alpenpanorama
setstate doif_TEST 2020-06-15 05:40:40 next_ARD_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 05:40:40 next_ARD_000_btime 05:30:00
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_000_desc Das ZDF-Morgenmagazin - der Blick in den Tag mit aktuellen hintergründigen Berichten und Gesprächen aus Politik Wirtschaft Sport und Kultur. Live aus dem ZDF-Hauptstadtstudio. Halbstündlich informiert die heute Xpress aus Mainz. Hinzu kommen Service-Beiträge mit Verbrauchertipps. Im Moma-Café treten Musiker live vor Publikum auf
setstate doif_TEST 2020-06-15 05:40:40 next_ARD_000_stitle [Frühmagazin, Infomagazin]
setstate doif_TEST 2020-06-15 05:40:40 next_ARD_000_title ZDF-Morgenmagazin
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_001_btime 09:00:00
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_001_desc Aktuelle Themen aus Politik Wirtschaft Kultur Sport Gesellschaft und Wissenschaft aus dem In- und Ausland werden in ausführlichen Hintergrundberichten beleuchtet. In Stellungnahmen und Meinungsäusserungen wird auch unterschiedlichne Standpunkten Raum gegeben
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_001_stitle Mit Wetter
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_001_title Tagesschau
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_002_btime 09:05:00
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_002_desc Das Vormittagsformat geht raus ins Leben Mit Live-Schalten zu den Menschen auf dem Land und in den Städten – immer auf der Suche nach Alltagshelden und Anpackern Menschen die unser Land am Laufen halten
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_002_stitle [Magazin, Infomagazin] Raus ins Leben
setstate doif_TEST 2020-06-15 05:40:41 next_ARD_002_title Live nach Neun
setstate doif_TEST 2020-06-15 07:40:43 next_AXN_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:43 next_AXN_000_btime 07:30:00
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_000_desc Jean-Marc Brouillard kehrt zur Wache 19 zurück und nimmt dort seine Rolle als Gewerkschaftsvertreter wieder auf. Das ist auch dringend notwendig da die Provinzregierung beschlossen hat die Renten im öffentlichen Sektor drastisch zu beschneiden. Dagegen will sich die Einheit zur Wehr setzen. Ben Chartier sieht sich währenddessen zu einer erneuten Konfrontation mit seiner Familie gezwungen.<br>Daniel Grou<br>Benz Antoine<br>Krista Bridges<br>Mikael Conde<br>Alexander De Jordy<br>Mylène Dinh-Robic<br>Marianne Farley<br>Juliette Gosselin<br>Adrian Holmes<br>Tattiawna Jones<br>Jared Keeso<br>Darcy Laurie<br>Laurence Leboeuf<br>Neil Napier<br>Dan Petronijevic<br>Joe Pingue<br>Bruce Ramsay<br>Chris Sandiford<br>Linda Smith<br>Vlasta Vrana
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_000_stitle Demonstration (2016) [16+]
setstate doif_TEST 2020-06-15 07:40:43 next_AXN_000_title 19-2
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_001_btime 08:20:00
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_001_desc Bens familiäre Situation verschlechtert sich weiterhin während Nick nicht aufhört nach dem Mörder seines Cousins zu suchen - er findet den angeblichen Mörder schliesslich in einem Striplokal. Martine erkennt ihn nicht wieder wohl aber dessen Begleiter...<br>Daniel Grou<br>Benz Antoine<br>Krista Bridges<br>Sabrina Campilii<br>Alexander De Jordy<br>Mylène Dinh-Robic<br>Juliette Gosselin<br>Samantha Hodhod<br>Adrian Holmes<br>Tattiawna Jones<br>Jared Keeso<br>Darcy Laurie<br>Laurence Leboeuf<br>Neil Napier<br>Dan Petronijevic<br>Joe Pingue<br>Bruce Ramsay<br>Linda Smith<br>Vlasta Vrana
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_001_stitle Verschwunden (2016) [16+]
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_001_title 19-2
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_002_btime 09:10:00
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_002_desc Albert und seine Freunde haben weder Gold noch Geld als sie sich auf den Weg zurück zum Haus von Norman machen. Kurz nachdem sie dort angekommen sind geben sich Albert und Vic gegenseitig die Schuld an ihrer misslichen Lage. Lily gelingt es den Streitereien ein Ende zu bereiten. Dann hat Albert eine Idee woraufhin er mit seinen Freunden und Vics Gang gemeinsam einen Plan schmiedet.<br>Nicholas Renton<br>Rupert Grint<br>Luke Pasqualino<br>Lucien Laviscount<br>Marc Warren<br>Stephanie Leonidas<br>Phoebe Dynevor<br>Juliet Aubrey<br>Tamer Hassan<br>Dougray Scott<br>Claire Cooper<br>Russ Bain<br>Vincent Regan<br>Johann Myers<br>Ian Gelder<br>Duncan Watkinson<br>Tarrick Benham
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_002_stitle Goldrausch (2017) [16+]
setstate doif_TEST 2020-06-15 07:40:44 next_AXN_002_title Snatch
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_000_btime 07:35:00
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_000_desc na
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_000_stitle (Live Rescue)Alligatoren-Rettung in Florida (2018) [12+]
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_000_title Live Rescue - Immer im Einsatz
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_001_btime 08:00:00
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_001_desc Mord scheint die geschäftliche Basis aller Aktivitäten der Mafia zu sein. Dies ist das Ergebnis einer Analyse bislang geheim gehaltener Akten des FBI. Die Fahnder haben nun ihre Archive geöffnet um deutlich zu machen dass die Mafia hinter zahllosen lange unaufgeklärten Todesfällen steckt. In dieser Episode berichten sie vom Aufstieg und Fall des Chicagoer Mafioso Sam Momo Giancana.<br>Martin Hughes<br>Sam Giancana<br>Fabio Vassallo.
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_001_stitle [Dokumentation, Zeitgeschichte]  (Mafias Greatest Hits)Der Strippenzieher: Sam Giancana (langeunaufgeklärtenTodesfällensteckt.IndieserEberichtensievomAufstiegu
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_001_title Im Netz der Mafia - Die Geheimakten des FBI
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:39 next_AandE_002_btime 08:50:00
setstate doif_TEST 2020-06-15 07:40:40 next_AandE_002_desc Mord scheint die geschäftliche Basis aller Aktivitäten der Mafia zu sein. Dies ist das Ergebnis einer Analyse bislang geheim gehaltener Akten des FBI. Die Fahnder haben ihre Archive geöffnet um deutlich zu machen dass die Mafia hinter zahllosen lange unaufgeklärten Todesfällen steckt. Die Reihe lässt nun die FBI-Agenten zu Wort kommen die die Morde des organisierten Verbrechens aufdeckten.
setstate doif_TEST 2020-06-15 07:40:40 next_AandE_002_stitle [Dokumentation, Zeitgeschichte]  (Mafias Greatest Hits)Der Reformer - Lucky Luciano (2012) [12+]
setstate doif_TEST 2020-06-15 07:40:40 next_AandE_002_title Im Netz der Mafia - Die Geheimakten des FBI
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_000_btime 07:15:00
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_000_desc Katzen sind dafür bekannt, dass sie gerne mal ungefragt um die Häuser stromern. Aber Princess Utah ist schon ein besonderer Fall. Der abtrünnige Stubentiger war immerhin für anderthalb Jahre verschwunden! Jetzt ist die Samtpfote wieder zurück zuhause, allerdings schwer verletzt. Kann das mehrfach gebrochene Bein des Rumtreibers noch gerettet werden? Oder bleibt am Ende nur die Amputation? Tierärztin Dr. Petra Young steht vor einer schwierigen Entscheidung. Außerdem in dieser Folge: Hausschwein Winnie muss unters Messer und Labrador Charlie hat den Werkzeuggürtel seines Besitzers verputzt. Jetzt befürchtet Dr. Jeff eine lebensbedrohliche Metallvergiftung bei dem gefräßigen Rüden
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_000_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_000_title Tierarzt Dr. Jeff - Der Rocky Mountain Doc: Episode 35
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_001_btime 08:00:00
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_001_desc Das Tierarzt-Team aus Denver startet zu einem abenteuerlichen Auslandseinsatz. Im mexikanischen Bundesstaat Yucatan bieten die Veterinäre kostenlose Behandlungen an. Entsprechend groß ist der Andrang, und die Reise mutiert zum reinsten Sterilisierungsmarathon. Für Managerin Melody ist es der erste Trip in das lateinamerikanische Land. Prompt wird sie ins kalte Wasser geworfen: In einem Hinterhof soll die gelernte Tierarztassistentin eine Horde herrenloser Katzen zähmen. Gemeinsam mit Dr. Andrés versucht sie die Unruhestifter zu bändigen - keine Chance! Später besucht Dr. Jeff ein Maya-Dorf in der Nähe von Valladolid. Doch die Wachhunde hier haben noch nie einen Tierarzt aus der Nähe gesehen
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_001_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_001_title Tierarzt Dr. Jeff - Der Rocky Mountain Doc: Into the Jungle
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_002_btime 08:45:00
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_002_desc Dr. Jeff Young ist immer dann zur Stelle, wenn Tiere in Not geraten, oder sich ihre Besitzer keinen Besuch beim Veterinär leisten können. Letzteres ist in South Dakota der Fall. Das Indianer-Reservat Rosebud wurde bereits vor über 120 Jahren gegründet und zählt heute zu den ärmsten Gebieten des Landes. Da die Menschen schlichtweg kein Geld für teure Tierarztrechnungen haben, bietet Dr. Jeff seine Behandlungen zum Nulltarif an. Ein Segen für die Lakota-Sioux-Gemeinde, die gemeinsam mit den Helfern ein Gebet zum Himmel schickt, bevor es an die Arbeit geht. Außerdem in dieser Episode: Bergkatze Nala hat ein ernstes Pfotenproblem und ein übergroßes Opossum hält die Tierärzte in Denver auf Trab
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_002_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:40 next_AnimalPlanet_002_title Tierarzt Dr. Jeff - Der Rocky Mountain Doc: The Dog Who Won Jeffs Heart
setstate doif_TEST 2020-06-15 06:55:32 next_DMax_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 06:55:32 next_DMax_000_btime 06:50:00
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_000_desc Das TV-Shopping Erlebnis bietet innovative, qualitativ hochwertige Produkte die den Alltag erleichtern zu einem sehr attraktiven Preis. Innovationen aus aller Welt werden zu einem unterhaltsamen Einkaufserlebnis. Das umfassende Produktportfolio beinhaltet die neuesten Produkte aus den Bereichen: Küche, Haushalt, Freizeit, Fitness, Wellness und Beauty. Die im Fernsehen gezeigten Produkte können telefonisch und auf der Website des Anbieters bestellt werden
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_000_stitle Werbesendung
setstate doif_TEST 2020-06-15 06:55:32 next_DMax_000_title Infomercial
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_001_btime 08:50:00
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_001_desc In dieser Episode von Hardcore Pawn wird einer Kundin im American Jewelry and Loan die 90-Tage-Frist zum Verhängnis. Werden verpfändete Wertgegenstände nach dieser vereinbarten Frist nicht abgeholt, geben Les Gold und seine Angestellten die Ware zum Verkauf frei, und der Besitzer hat keinen Anspruch auf Rückerstattung. Die Geschäftsbedingungen sind der betreffenden Dame durchaus bekannt, trotzdem macht sie im Laden heftig Krawall
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_001_stitle Doku-Soap
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_001_title Hardcore Pawn - Das härteste Pfandhaus Detroits: Episode 9
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_002_btime 09:20:00
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_002_desc Eine Kunde möchte im American Jewelry and Loan ein Akkordeon zu Geld machen. Doch das Musikinstrument befindet sich in miserablem Zustand, deshalb kann ihm Les Gold nicht den gewünschten Betrag ausbezahlen. Der Mann scheint sich in einer akuten finanziellen Notlage zu befinden, deshalb bietet er den Pfandleihern anschließend sogar seine Prothese an. Doch auch diese ist leider nicht viel wert
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_002_stitle Doku-Soap
setstate doif_TEST 2020-06-15 06:55:33 next_DMax_002_title Hardcore Pawn - Das härteste Pfandhaus Detroits: Episode 10
setstate doif_TEST 2020-06-15 07:40:43 next_History_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:43 next_History_000_btime 07:15:00
setstate doif_TEST 2020-06-15 07:40:43 next_History_000_desc Der Autor Seifer der Astrophysiker Taylor und der Journalist Stapleton wollten das Rätsel um den Tod des Erfinders Tesla entschlüsseln. Stapleton und Taylor untersuchten eine Verbindung zwischen Teslas letztem Patent und einem der fortschrittlichsten Flugzeuge der Air Force. Schliesslich stellten sie einen Zusammenhang zwischen dem Wardenclyffe Tower und dem Hotel The New Yorker fest
setstate doif_TEST 2020-06-15 07:40:43 next_History_000_stitle [Doku-Serie]  (The Tesla Files)Militärischer Nutzen (2018) [12+]
setstate doif_TEST 2020-06-15 07:40:43 next_History_000_title Das Tesla-Vermächtnis
setstate doif_TEST 2020-06-15 07:40:43 next_History_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:43 next_History_001_btime 08:00:00
setstate doif_TEST 2020-06-15 07:40:43 next_History_001_desc Der österreichische Oscar-Preisträger Maximilian Schell erzählt von dem Aufstieg und dem Fall der europäischen Ritter. Die gepanzerten Kämpfer waren zu ihrer Zeit die Helden des Mittelalters furchtlose Kämpfer für Kaiser und Kirche kurzum die militärische Elite des Abendlandes. Die Ritter wurden in den Krieg gegen moslemische Glaubenskämpfer geschickt die den Islam in die Welt tragen wollten
setstate doif_TEST 2020-06-15 07:40:43 next_History_001_stitle [Doku-Serie] Der letzte Kampf der Ritter (2011) [12+]
setstate doif_TEST 2020-06-15 07:40:43 next_History_001_title Imperium
setstate doif_TEST 2020-06-15 07:40:43 next_History_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:43 next_History_002_btime 08:45:00
setstate doif_TEST 2020-06-15 07:40:43 next_History_002_desc Der Oscar-Preisträger Maximilian Schell stellt so berüchtigte Seeräuber wie Sir Francis Drake Blackbeard William Kidd und Olivier Levasseur vor furchtlose Piraten die im 16. und 17. Jahrhundert zu Recht von Schiffsreisenden gefürchtet wurden. Die legendären Schatzräuber waren aber oftmals im Namen einer Majestät unterwegs um die beladenen Handelsschiffe der politischen Gegener zu kapern
setstate doif_TEST 2020-06-15 07:40:43 next_History_002_stitle [Doku-Serie] Das Gold der Piraten (2011) [12+]
setstate doif_TEST 2020-06-15 07:40:43 next_History_002_title Imperium
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_000_btime 07:10:00
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_000_desc Einst teilten sich die Menschen mit mächtigen Göttern des Tierreichs die Erde. Doch das friedliche Zusammensein findet ein jähes Ende, als die Menschen versuchen, sich immer mehr Lebensraum der Tiere anzueignen. Ein erbitterter Kampf entsteht, dessen Folgen unter anderem ein junger Prinz namens Ashitaka tragen muss. Er wurde mit einem tödlichen Fluch belegt und muss nun auf Hilfe des Waldgottes hoffen, wenn er überleben will. Das von Wölfen adoptierte Mädchen San hilft ihm dabei
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_000_stitle Animefilm
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_000_title Prinzessin Mononoke
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_001_btime 09:20:00
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_001_desc Wer bin ich? - Mit diesem Aufsatzthema lässt Rektor Vernon fünf seiner missratenen Schüler an einem Samstagmorgen in der Bibliothek zum Nachsitzen zurück. Brian, John, Andrew, Claire und Allison sind grundverschieden und alles andere als Freunde, doch eingepfercht in der Institution, die sie auf das wahre Leben vorbereiten soll, lernen sie einander kennen, ihre Ängste, Probleme und ihre Sehnsüchte. Doch wird das, was die jungen Erwachsenen an diesem Samstag verbindet, andauern
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_001_stitle Drama
setstate doif_TEST 2020-06-15 07:10:34 next_KabelEinsClassic_001_title Breakfast Club - Der Frühstücksclub
setstate doif_TEST 2020-06-15 07:10:35 next_KabelEinsClassic_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:10:35 next_KabelEinsClassic_002_btime 10:55:00
setstate doif_TEST 2020-06-15 07:10:35 next_KabelEinsClassic_002_desc Psychodrama nach einer wahren Begebenheit: Die Hausfrau und fürsorgliche Mutter Peggy Blankenship wird mit über 40 Axthieben brutal ermordet. Bereits nach kurzer Zeit steht fest, dass eine Bekannte der Familie, Candy Morrison, die Täterin ist. Alles deutet auf ein entsetzliches Verbrechen hin, jedoch plädiert Morrison auf Notwehr. Nun liegt ihr Schicksal in den Händen der Jury .
setstate doif_TEST 2020-06-15 07:10:35 next_KabelEinsClassic_002_stitle Kriminalfilm
setstate doif_TEST 2020-06-15 07:10:35 next_KabelEinsClassic_002_title Die Axtmörderin
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_000_btime 07:00:00
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_000_desc Die Doku-Reihe begleitet ein Familienbusiness von Transportspezialisten mit einer anspruchsvollen Aufgabe: dem Transport der weltweit schwersten, längsten und wertvollsten Züge und Lokomotiven
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_000_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_000_title Mission Schwertransport - Züge: Der gigantische Kran
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_001_btime 07:45:00
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_001_desc Die Doku-Reihe begleitet ein Familienbusiness von Transportspezialisten mit einer anspruchsvollen Aufgabe: dem Transport der weltweit schwersten, längsten und wertvollsten Züge und Lokomotiven
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_001_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:33 next_KabelEinsDoku_001_title Mission Schwertransport - Züge: Hochgeschwindigkeitszug
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_002_btime 08:35:00
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_002_desc Die Crew transportiert heute eine gigantische Gleisbaumaschine über Land- und Seewege sowie einen tonnenschweren Dieselmotor quer durch die Republik
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_002_stitle Reality-Soap
setstate doif_TEST 2020-06-15 07:40:34 next_KabelEinsDoku_002_title Mission Schwertransport - Züge: Die Gleisbaumaschine auf Reisen
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_000_btime 06:55:00
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_000_desc Laura Ingalls hat sich Hals über Kopf in ihren wesentlich älteren Mitschüler Johnny Johnson verliebt. Obwohl Johnny sie in keiner Weise ermutigt, versucht Laura alles, um ihren Schwarm auf sich aufmerksam zu machen. Doch Johnny interessiert sich mehr für eine andere - und das ist ausgerechnet Lauras Schwester Mary. Schließlich bittet Johnny Mary darum, ihm Nachhilfeunterricht im Lesen und Schreiben zu geben. Zwischen den Schwestern kommt es zu einer heftigen Krise
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_000_stitle Familienserie
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_000_title Unsere kleine Farm: Erste Liebe
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:25:33 next_Kabel_001_btime 07:55:00
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_001_desc Der Mord an einem Diplomaten führt Sam und Callen nach Mexico: Der ehemalige Killer Tuhon, mit dem es das Duo in seinem allerersten Fall zu tun hatte, soll in das Verbrechen verwickelt sein. Nun gilt es, den Mann aufzuspüren und herauszufinden, inwieweit er wirklich in die Sache involviert ist. Unterdessen versucht Kensi in Afghanistan immer noch aufzuklären, was es mit White Ghost auf sich hat
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_001_stitle Krimiserie
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_001_title Navy CIS: L.A.: Tuhon
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_002_btime 08:45:00
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_002_desc Auf einem Schiff der Navy wird der zuständige Mannschaftsarzt tot aufgefunden. Während des Verhörs der Crew macht McGee eine unliebsame Entdeckung: Sein Vater, Admiral McGee, ist ebenfalls Mitglied der Besatzung und strebt eine politische Karriere in Washington an. Da das gemeinsame Verhör nicht gut läuft, nimmt Gibbs McGee Senior zur Seite und erfährt, dass er Krebs im Endstadium hat, wovon der tote Arzt wusste. Wurde ihm das zum Verhängnis
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_002_stitle Krimiserie
setstate doif_TEST 2020-06-15 07:25:34 next_Kabel_002_title Navy CIS: Die weiße Bö
setstate doif_TEST 2020-06-15 07:40:40 next_Kinowelt_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_000_btime 07:20:00
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_000_desc Spezialpreis der Jury, Cannes Nominiert für die Goldene Palme, Cannes Die junge Vittoria verlässt ihren Freund Riccardo nach einer langen Nacht im Streit. Vittoria sehnt sich nach wahrer Liebe. Als sie ihre Mutter, die sich als Spekulantin an der römischen Börse, versucht besucht, begegnet Vittoria dem attraktiven Spekulanten Piero. Langsam kommen sie sich näher. Aber sind beide fähig, das Wagnis der Liebe einzugehen? Michelangelo Antonionis Melodrama erzählt von der Unfähigkeit zu lieben. In starken, symbolisch aufgeladenen Bildern durchleben Alain Delon und Monica Vitti die ganze Brüchigkeit menschlicher Beziehungen. In Cannes wurde der Film mit dem Sonderpreis der Jury ausgezeichnet. Am Beispiel eines aus kleinen Verhältnissen stammenden römischen Mädchens, das zwischen zwei Männern steht, greift Michelangelo Antonioni das Thema der Kontaktlosigkeit und Liebesunfähigkeit des modernen Menschen auf. (Quelle: VideoMarkt) kino-zeit.de schreibt: Das, was hier unaussprechlich transportiert wird, lässt sich schwerlich in Verbales übersetzen, so dass eine ausgesprochen eindringliche Macht der Bilder und Bewegungen entsteht, die Michelangelo Antonioni als wahres Regie-Talent auszeichnen, das damit die Verfinsterungen der Liebe äußerst ansprechend visualisiert hat
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_000_stitle Liebesfilm
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_000_title Liebe 1962
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_001_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_001_btime 09:20:00
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_001_desc Nachdem Michael Faraday seine Frau bei einem FBI-Einsatz verloren hat, versucht er trotz seiner obsessiven Beschäftigung mit Terrorismus mit seinem Sohn ein normales Leben zu führen. Dabei helfen könnte ihm auch die Freundschaft zum neuen Nachbar Oliver Lang. Der aber verfolgt Pläne, die nicht nur für Faraday verhängnisvolle Folgen haben könnten. Terror is coming home! Und er nistet sich direkt in der Nachbarschaft einer ganz normalen US-Familie ein. Bereits vor 9/11, 24 und Homeland hat die Terrorparanoia tiefe Wunden ins amerikanische Sozialgefüge gerissen und im sensationell spannenden Thriller von Mark Pellington stargespickten und verstörenden Ausdruck gefunden
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_001_stitle Psychothriller
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_001_title Arlington Road
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_002_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_002_btime 11:15:00
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_002_desc Hollywoods Best Film Directors erzählt die Geschichten der herausragendsten Regisseure der letzten Jahrzehnte und offenbart das Geheimnis ihres Erfolgs! In dieser Episode geht es auf einen Trip in den hochintelligenten und kreativen Kopf von Danny Boyle. Durch seinen Kultklassiker Trainspotting mit Ewan McGregor wurde er 1996 mit einem Schlag berühmt. Danach fuhr er mit Leonardo DiCaprio für The Beach ins thailändische Paradies, das keines war, und stellte sich bei der Realisierung von 127 Hours der Herausforderung, mit nur einem einzigen Schauspieler, James Franco, einen ganzen Film zu drehen. Der biografische Film, der auf dem Buch von Bergsteiger Aron Ralston basiert, wurde für sechs Academy Awards nominiert. Darauf folgte das beeindruckende Biopic über den Apple Gründer Steve Jobs mit einem herausragenden Cast. Den meisten Zuschauern wird Danny Boyle jedoch bekannt sein durch seine berührende Geschichte über den Slumdog Millionär
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_002_stitle Film/Kino/TV
setstate doif_TEST 2020-06-15 07:40:41 next_Kinowelt_002_title Hollywoods Best Film Directors - Danny Boyle
setstate doif_TEST 2020-06-15 07:10:42 next_N24Doku_000_bdate 2020-06-15
setstate doif_TEST 2020-06-15 07:10:43 next_N24Doku_000_btime 07:05:00
setstate doif_TEST 2020-06-15 07:10:43 next_N24Doku_000_desc Wo Wohnraum knapp ist wird in die Höhe gebaut. In vielen Metropolen prägen gigantische Wohnblöcke das Stadtbild. Oft befinden sie sich in städtischen Brennpunkten. Neue Bauten sollen die sozialen Ungleichheiten innerhalb der Ballungsr
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 09:46:08
Du must die Formatierung hier anpassen:

$TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{1..6} = "border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\


Wenn du also lediglich einen Sender eingefügt hast müsste es so aussehen:

$TR{0,32} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..30,32..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..30,32..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..61}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{31}{1..6} = "border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juni 2020, 09:47:53
Verstanden, danke dir.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 09:49:30
@Cwagner: Wenn du Fehlermeldungen wie blocking call aborted im logfile siehst, dann stimmt da was grundsätzlich nicht und dein System rennt in einer Dauerschleife rum. Dann ist es auch nicht verwunderlich wenn andere Prozesse Probleme bekommen. Hast du noch mal die angepasste Version aus dem ersten Beitrag verwendet?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 15 Juni 2020, 10:11:37
Zitat von: mumpitzstuff am 15 Juni 2020, 09:49:30
@Cwagner: Wenn du Fehlermeldungen wie blocking call aborted im logfile siehst, dann stimmt da was grundsätzlich nicht und dein System rennt in einer Dauerschleife rum. Dann ist es auch nicht verwunderlich wenn andere Prozesse Probleme bekommen. Hast du noch mal die angepasste Version aus dem ersten Beitrag verwendet?

Als ich noch OWX-Module einsetzte war pro 1820-Device eine "Sendepause" von ca. einer Sekunde (mit apptime nachweisbar). Ich habe das Problem lange Zeit auf mein FHEM-System unter Windows geschoben. Nachdem ich auf pi4 umgestiegen bin, war das Problem immer noch da. Daraufhin habe ich 1-Wire über ESP-Easy eingebunden und die Probleme waren weg (ebenfalls über apptime nachweisbar).

@Cwagner du kannst mit apptime sehen, wie viel Zeit sich ein Modul mit seiner Abarbeitung lässt, dann hast du schnell den Schuldigen, dann kannst du ihn vorübergehend abschalten und schauen, ob es immer noch zu Abbrüchen bei blocking call kommt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 15 Juni 2020, 10:23:58
Zitat von: mumpitzstuff am 14 Juni 2020, 21:15:02
PS: Im ersten Beitrag habe ich das DOIF noch mal geändert, so das man Time::Piece nicht mehr braucht. Man kann es aber manuell in der Funktion xmltv2epoch einschalten, wenn man es möchte.

Mit dieser geänderten Version funktioniert es bei mir jetzt ohne andere Module auszuknocken: Ich erhalte zumindest die erste Tabelle gefüllt (Prime-Time ist (noch?) leer).

Allerdings erhalte ich immer beim Update der Reedings für die erste Tabelle einen Fehler der Oberfläche, wie im Screenshot abgebildet. Es ist nicht spezifisch für den Raum, aber es kommt immer ein paar Mal während der update-Verarbeitung.

System ist auf Update-Stand von gestern.

Herzliche Grüße

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 15 Juni 2020, 10:31:21
Zitat von: Damian am 15 Juni 2020, 10:11:37
Als ich noch OWX-Module einsetzte war pro 1820-Device eine "Sendepause" von ca. einer Sekunde (mit apptime nachweisbar). ... du kannst mit apptime sehen, wie viel Zeit sich ein Modul mit seiner Abarbeitung lässt, dann hast du schnell den Schuldigen, dann kannst du ihn vorübergehend abschalten und schauen, ob es immer noch zu Abbrüchen bei blocking call kommt.
Vielen Dank @Damian für den wertvollen Hinweis; dem werde ich auf jeden Fall nachgehen. Möglicherweise komme ich mit dem TV-Programm während der Verarbeitung tatsächlich an die "Toleranzgrenze" des Systems auf einem PI3.
Die vom Autor gemachte Änderung (andere Bibliothek für das Zeiten-Rechnen) hat aber auch schon zu einer erheblichen Verbesserung geführt.

Herzliche Grüße

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 15 Juni 2020, 10:35:51
Zitat von: cwagner am 15 Juni 2020, 10:23:58
Mit dieser geänderten Version funktioniert es bei mir jetzt ohne andere Module auszuknocken: Ich erhalte zumindest die erste Tabelle gefüllt (Prime-Time ist (noch?) leer).

Allerdings erhalte ich immer beim Update der Reedings für die erste Tabelle einen Fehler der Oberfläche, wie im Screenshot abgebildet. Es ist nicht spezifisch für den Raum, aber es kommt immer ein paar Mal während der update-Verarbeitung.

System ist auf Update-Stand von gestern.

Herzliche Grüße

Christian

Die Meldung kommt, wenn man im generierten HTML-Code einfache Anführungszeichen angibt: ' - es müssen immer die doppelten sein: ", sonst kann es der Javascript-Prozess nicht sauber auswerten.

Edit: ich habe die Aussage gerade korrigiert, es war andersrum.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 11:25:31
Okay das mit dem Fehler muss ich mir ansehen. In meinem FHEM habe ich das glaube ich ausgeschaltet, deshalb ist mir das nicht aufgefallen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juni 2020, 11:40:25
Wollte ich auch ausschalten, aber ich finde nicht, wie es geht.
Habe die gleiche Fehlermeldung.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 11:41:01
Ich glaube ich habs gefunden. Ein ganz blöder Bug.

Schau mal bitte in das Attribut uiTable und such die folgende Zeile:

$TD{30}{1..6} = "border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;'";

das muss man ersetzen durch:

$TD{30}{0..6} = "style='border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;'";

Den ersten Beitrag passe ich gleich entsprechend an.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 11:41:55
wenn es immer noch kommt bitte melden, dann ist da noch was anderes.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 11:45:35
Im WEB Device kann man das Attribut confirmJSError auf 0 setzen, dann verschwinden die Fehler auch.

PS: Wenn prime noch nicht gefüllt ist, dann einfach noch etwas warten. Das wird jede Nacht um 0:30 Uhr gemacht, sollte also Morgen dann sichtbar sein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juni 2020, 11:57:20
Vielen Dank, habs getauscht. Mal gucken.
Java Fehlermeldungen abschalten hatte ich gesucht, aber nicht gefunden. Auch da danke für den Tipp.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 15 Juni 2020, 13:11:24
Ich würde erst mal nach den Ursachen suchen, bevor ich die Meldungen abschalte. All meine uiTable-Funktionen, die HTML-Code generieren, produzieren keine Fehlermeldung. Das sollte immer das Ziel sein, sonst funktioniert etwas nicht richtig. Wie schon gesagt: Auf keinen Fall einfache Anführungszeichen im HTML-Code verwenden.

Bsp.:
statt:

$TD{30}{0..6} = "style='border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;'";


$TD{30}{0..6} = 'style="border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;"';

definieren.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juni 2020, 13:13:35
Ich denke, mit der Korrektur ist der Fehler beseitigt. Keine Meldungen bisher. Dnke nochmals.


EDIT
Zu früh gejubelt. Fehlermeldung ist wieder da.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 15 Juni 2020, 13:21:30
Zitat von: Invers am 15 Juni 2020, 13:13:35
Ich denke, mit der Korrektur ist der Fehler beseitigt. Keine Meldungen bisher. Dnke nochmals.


EDIT
Zu früh gejubelt. Fehlermeldung ist wieder da.

Bei $TD, $TC dürfte es nicht das eigentliche Problem sein, es war nur ein Beispiel. Das Problem ist dann gegeben, wenn eine eigene Perlfunktion den HTML-Code generiert - das dürften in der gesamten DOIF-Definiton hier einige Perlfunktionen sein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 14:34:33
Dann kommt das Problem aus dieser Zeile:

return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";;\

Mir ist aber unklar, wie ich das Problem hier umgehen soll. Ich brauche hier eine Verschachtelung und diese ist nur mit " nicht realisierbar. onClick selbst muss mit " umgeben sein und der String der der Funktion FW_okDialog übergeben wird muss ebenfalls mit irgendwas umgeben sein. " kann ich an der Stelle nicht verwenden, also bleibt nur '. Im Moment habe ich keine Ahnung was ich da machen könnte.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 16:42:54
Kannst du bitte mal versuchen, im Attribut uiTable die oben genannte Zeile durch diese zu ersetzen?

return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";

Ich habe zwar den Fehler einmal sehen können, nachdem ich die Javascript Fehler aktiviert hatte, jetzt tauchen sie bei mir aber gar nicht mehr auf und ich kann nicht prüfen, ob sie immer noch vorhanden sind oder nicht.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Frank_Huber am 15 Juni 2020, 17:18:26
Zitat von: mumpitzstuff am 15 Juni 2020, 16:42:54
Kannst du bitte mal versuchen, im Attribut uiTable die oben genannte Zeile durch diese zu ersetzen?

return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";

Ich habe zwar den Fehler einmal sehen können, nachdem ich die Javascript Fehler aktiviert hatte, jetzt tauchen sie bei mir aber gar nicht mehr auf und ich kann nicht prüfen, ob sie immer noch vorhanden sind oder nicht.

Fehler ist damit weg.

Eine Frage aus dem Thread ist noch offen:
Welche Icons hast Du gezogen?
Die von AVM müssen ja so wie es aussieht alle umbenannt werden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 17:49:12
Ich glaube von Klack.de hatte ich die kopiert. Ich musste sie aber ebenfalls alle umbenennen. Alternativ kannst du aber auch im uiTable Attribut die Namen an deine Dateinamen anpassen. Beide Wege führen zum selben Ziel.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 15 Juni 2020, 20:53:37
Zitat von: mumpitzstuff am 15 Juni 2020, 16:42:54
Kannst du bitte mal versuchen, im Attribut uiTable die oben genannte Zeile durch diese zu ersetzen?

return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";


In der Tat, damit ist bei mir der "uncaught error" auch weg.

Danke
Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juni 2020, 21:38:13
Ich habe den ersten Beitrag entsprechend abgeändert (Javascript Bug ist damit hoffentlich behoben). Die Benutzung von Time::Piece ist jetzt per Variable konfigurierbar (default = disabled). Außerdem habe ich einige Debug Meldungen bei höheren Verbose Level hinzugefügt. Level 5 sollte man nur im äußersten Notfall verwenden, das wird jede Menge Daten ausspucken.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 15 Juni 2020, 21:46:04
Zitat von: mumpitzstuff am 15 Juni 2020, 21:38:13
Ich habe den ersten Beitrag entsprechend abgeändert (Javascript Bug ist damit hoffentlich behoben). Die Benutzung von Time::Piece ist jetzt per Variable konfigurierbar (default = disabled). Außerdem habe ich einige Debug Meldungen bei höheren Verbose Level hinzugefügt. Level 5 sollte man nur im äußersten Notfall verwenden, das wird jede Menge Daten ausspucken.

Der Javascript Bug ist mit dieser Lösung auf jeden Fall behoben. Ich werde den wichtigen Hinweis: "Keine einfachen Anführungszeichen beim selbst generierten Code verwenden" in uiTable-Wiki aufnehmen und die Alternative mit ' für eine erforderliche Hierarchie angeben.

Edit: Es ist eigentlich kein Javascript Bug, sondern dieser Update-Mechanismus im DOIF:         

FW_directNotify("#FHEMWEB:$_", "doifUpdateCell('$pn','doifId','$doifId','$value','display:inline-table;$style')","");

deswegen darf im HTML-Code hier $value kein einfaches Hochkomma vorkommen
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 16 Juni 2020, 07:22:50
Zitat von: mumpitzstuff am 15 Juni 2020, 11:45:35
Wenn prime noch nicht gefüllt ist, dann einfach noch etwas warten. Das wird jede Nacht um 0:30 Uhr gemacht, sollte also Morgen dann sichtbar sein.
Stimmt, nach 0:30 Uhr ist nun auch prime gefüllt.
Vielen Dank
Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Frank_Huber am 16 Juni 2020, 07:30:57
Ja, top!
Alles da. 👍🏻👍🏻👍🏻

Die Infos wegen den Icons und der Prime Time wären im ersten Post auch ganz gut aufgehoben. 😉
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 16 Juni 2020, 07:46:20
Läuft alles. Ein Meisterwerk Danke.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: moonsorrox am 16 Juni 2020, 14:57:15
eine Frage zu den Iconsnamen, welchen muss ich denn genau ändern, es gibt ja Groß- und Kleinschreibung ,oder beide.?
TPL_TV($SELF,next,ARD,ard)\
"das_erste_hd.png" heißt ja die Download Datei.

Dann noch ein Problem mit der Größe der Icons ZDF und Pro 7 ist riesen groß gegen das_erste_hd
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Frank_Huber am 16 Juni 2020, 15:09:17
Zitat von: moonsorrox am 16 Juni 2020, 14:57:15
eine Frage zu den Iconsnamen, welchen muss ich denn genau ändern, es gibt ja Groß- und Kleinschreibung ,oder beide.?
TPL_TV($SELF,next,ARD,ard)\
"das_erste_hd.png" heißt ja die Download Datei.
wenn ich das im Thread richtig gelesen habe ist es der letzte Wert. also "ard.png"
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: moonsorrox am 16 Juni 2020, 15:37:55
OK Danke werde ich mal anpassen.

Ich habe jetzt festgestellt das man das in den Blöcken machen muss und wenn man es im uiTable Attribut vergißt ändert sich das auch im Blöck nicht...
Das war bei mir das Problem  :-\
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 16 Juni 2020, 16:39:37
Zitat von: moonsorrox am 16 Juni 2020, 15:37:55
OK Danke werde ich mal anpassen.

Ich habe jetzt festgestellt das man das in den Blöcken machen muss und wenn man es im uiTable Attribut vergißt ändert sich das auch im Blöck nicht...
Das war bei mir das Problem  :-\

Man kann sicherlich noch einiges optimieren. Es ist die erste größere Anwendung mit DOIF-Perl und uiTable.

Man kann z. B. Devicevariablen, die man im Perlblock belegt in der uiTable nutzen.

Ebenso kann man mit dem FOR-Befehl viele uiTable-Zeilen ersetzen.

Aber erst soll die Sache stabil Laufen, dann kann ich noch mal drüber schauen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 17 Juni 2020, 02:26:28
Ich habe im ersten Beitrag noch mal diverse Quellen für Senderlogos verlinkt (die ersten beiden sind besonders gut). Wenn man schöne svg Icons hat, dann kann man diese leicht umwandeln z.B. hier:

https://svgtopng.com/de/ (https://svgtopng.com/de/)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 17 Juni 2020, 08:02:27
Zitat von: mumpitzstuff am 17 Juni 2020, 02:26:28
Ich habe im ersten Beitrag noch mal diverse Quellen für Senderlogos verlinkt (die ersten beiden sind besonders gut) und auch meine aktuellen als zip angehangen. Wenn man schöne svg Icons hat, dann kann man diese leicht umwandeln z.B. hier:

Vielen Dank, mumpitzstuff. Eines gelingt mir noch nicht. Du schriebst:


4.) Wenn man Sender hinzufügen möchte, dann kann man sich die original xml Dateien runterladen und die entsprechenden Sender raus suchen. Danach muss man folgende Dinge anpassen (wenn man einen Sender entfernen möchte, muss man die entsprechenden Dinge ebenfalls anpassen):

Ich suche in den verarbeiteten rytecDE_Basic auf meinem PI Sender wie NDR oder auch arte vergeblich, um sie in die Filterliste aufzunehmen. 3sat hat beispielsweise sehr gut funktioniert, die finde ich aber auch in den Daten vom ersten Tag an.


Vielen Dank für einen Tipp im Voraus

Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 17 Juni 2020, 09:06:35
Die XML Dateien musst du dir manuell im Browser auf deinen Rechner holen. Das DOIF hat einen Schalter gesetzt, der die lokalen XML Dateien um alle nicht benötigten Sender bereinigt. Das geschieht aus Optimierungszwecken, was man in der Config Area im DOIF aber auch abschalten kann. Eine optimierte xml Datei ist nur noch 4MB groß. Würde ich das nicht tun, wäre die Datei rund 20mb groß, was dein System aber unnötig belasten würde.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: cwagner am 17 Juni 2020, 17:58:44
Zitat von: mumpitzstuff am 17 Juni 2020, 09:06:35
Die XML Dateien musst du dir manuell im Browser auf deinen Rechner holen. Das DOIF hat einen Schalter gesetzt, der die lokalen XML Dateien um alle nicht benötigten Sender bereinigt. Das geschieht aus Optimierungszwecken, was man in der Config Area im DOIF aber auch abschalten kann. Eine optimierte xml Datei ist nur noch 4MB groß. Würde ich das nicht tun, wäre die Datei rund 20mb groß, was dein System aber unnötig belasten würde.
Verstanden und klappt, wenn ich die in den Texten die hinter channel= stehenden Namen ohne das .de nehme.
Jetzt beginnt die individuelle Programmzeitung richtig gut zu laufen!

Grüße
Christian
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 17 Juni 2020, 20:04:13
Hier kann man z.B. auch sehen was es sonst noch alles gibt.

http://rytecepg.dyndns.tv/epg_data/ (http://rytecepg.dyndns.tv/epg_data/)

Im DOIF werden nur die beiden Dateien rytecDE_Basic.xz und rytecDE_Common.xz geladen und gemerged. Das bdedeutet, das man aktuell nur Sender aus diesen beiden Dateien anzeigen lassen kann. Es gibt aber die Möglichkeit weitere Dateien zu mergen und dann ebenfalls anzeigen zu lassen wie z.B. rytecDE_SportMovies.xz.

Dazu muss man einfach die Funktion "sub tvDownloadMerge()" suchen und diese ersetzen:

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');

    # download and merge other files here if needed
   
    return $output;
  }


durch

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_SportMovies.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_SportMovies.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');
    tvMerge($_dataFile, $_path.'rytecDE_SportMovies');

    # download and merge other files here if needed
   
    return $output;
  }


ersetzen. Das Spiel lässt sich beliebig fortsetzen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 18 Juni 2020, 17:13:26
 :) :) :) :) :)   Vielen Dank für dieses tolle DOIF.    :) :) :) :) :)


Funktioniert viel besser und leichter als andere Lösungen zum EPG.

Wenn ich einen Link in Fhem anklicke erscheint das Popup mit den Detailinfotexten perfekt.

Ich habe das DOIF per

<div data-type="readingsgroup" data-device="doif_TEST"></div> 

in FTUI eingebaut, hier funktioniert der Link nicht und im Toastmessage wird ausgegeben: ReferenceError:FW_okDialog is not defined.

Vielen Dank für einen Tipp im Voraus!
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 18 Juni 2020, 17:29:12
Ich habe da noch eine Anregung zur Erweiterung des DOIFS!!!

In Ftui habe ich eine Liste mit Senderlogos zusammengebastelt, die ich zum Umschalten meines SAT-Receivers per IR-Blaster nutze.

Das möchte ich gerne mit dem DOIF zusammenfassen, da die Liste der Senderlogos ja schon vorhanden ist.


Dazu nutze ich:   

<div data-type="push" data-cmd="set" data-device="irblaster" data-set="send" data-set-on="IR_SAT_DasErste"       data-background-icon="" data-icon="" class="inline senderliste" style="background-image: url('img/sender/daserste.png');"></div>

Alternativ wäre ich auch schon glücklich, wenn in der Senderliste ein Command alla "set irblaster IR_SAT-DasErste" als Link beim Anklicken des Senderlogos aufgerufen würde.

z.B.:

TPL_TV($SELF,next,ARD,ard,set irblaster IR_SAT-DasErste)\


Vielleicht habt Ihr einen Tipp für mich, da meine Programmierkünste dafür nicht reichen. :) 
         
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 18 Juni 2020, 21:12:33
Den Dialog stellt FHEMWEB zur Verfügung, deshalb kann das unter FTUI nicht funktionieren. Gibt es denn Popup Dialoge in FTUI, die ich per onClick über JavaScript aufrufen kann?

Das andere mit dem Umschalten deines Fernsehers sollte gehen. Die entsprechende Erweiterung baue ich die Tage ein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 18 Juni 2020, 21:44:42
Was passiert wenn du im Attribut uiTable das hier:

return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";

durch das hier ersetzt?

return "<div data-type=\"popup\"><div>".$title."</div><div class=\"dialog\"><header>Details</header><div>".$desc."</div></div></div>";

Ist ungeprüft, kann also Fehler enthalten. Eventuell muss ich für diese Variante auch bestimmte Zeichen filtern, das müsste ich mir im Detail ansehen. Aber erst mal muss ich wissen ob das überhaupt ansatzweise geht.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: moonsorrox am 19 Juni 2020, 13:06:09
ich bin auch noch ein wenig am testen, aber meine Frage dazu ich habe das zweimal untereinander ist das normal?
Aber der untere Teil füllt sich nicht.!
siehe Screenshot
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Frank_Huber am 19 Juni 2020, 13:10:59
Zitat von: moonsorrox am 19 Juni 2020, 13:06:09
ich bin auch noch ein wenig am testen, aber meine Frage dazu ich habe das zweimal untereinander ist das normal?
Aber der untere Teil füllt sich nicht.!
siehe Screenshot
füllt sich um 00:30 ca.
das ist die "Prime Time Liste"
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: moonsorrox am 19 Juni 2020, 13:12:42
ichhabe das ca. 5 Tage schon am laufen, aber es ist immer noch leer  ;)

Ich habe mal die Zeit geändert um zu schauen, ich muss dazu sagen ich habe das auf meinem Test System in der VM laufen, die geht nachts aber aus...! aber eigentlich nie vor 01:00 Uhr
Alles klar es funktioniert...!  ;)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 19 Juni 2020, 14:53:29
Dann musst du wohl die Zeiten etwas anpassen und das z.b. auf früh um 8 ändern. Du must aber darauf achten, das der Download vor dem aktualisieren der prime Sendungen stattfindet.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: moonsorrox am 19 Juni 2020, 14:55:42
Ja, Danke schon kapiert, war wohl die VM schon jedesmal runter gefahren  :) ;)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 19 Juni 2020, 18:52:13
Hallo mumpitzstuff,

vielen Dank für die schnelle Reaktion.

Deine geänderte Zeile führt dazu, daß in FHEM die $desc. in der Übersicht sofort mitangezeigt werden. Hier müßte später wenn es funktioniert noch eine Fallunterscheidung FHEM oder FTUI getroffen werden damit das DOIF universell verwendbar bleibt.

Das FTUI popup Widget sollte gut geeignet sein um das Problem zu lösen!

In FTUI passiert leider beim Anklicken eines $title bei mir nichts, ich habe das auch mit

return "<div data-type=\"popup\"> <data-height=\"500px\"> <data-width=\"500px\"<div>".$title."</div><div class=\"dialog\"><header>Details</header><div>".$desc."</div></div></div>";

getestet, da ich vermutet habe daß das POPUP zu klein für längere Texte ist.

Ein Mustertext funktioniert aber mit

<li data-row="8" data-col="8" data-sizex="3" data-sizey="5">
      <header>Popup</header>
               <div class="sheet">
                  <div class="cell">
                     <div data-type="popup"
                         data-height="500px"
                          data-width="500px"
                        <div>Hier klicken um Popup zu öffnen</div>
                              <div class="dialog">
                                 <header>Popup</header>
                                 <div>Inhalt des Popups<br>
                                  Gefragt - Gejagt<br>
                                    Details<br>
                                    (2020)<br>
                                    Moderator Alexander Bommes begrüsst in jeder Ausgabe vier
                                    Kandidaten. In der ersten Runde werden den Kandidaten einzeln
                                    Fragen gestellt. Für jede richtige Antwort erhält man 500 Euro.
                                    Das erspielte Geld muss jeder Kandidat zunächst einzeln gegen
                                    einen Quizprofi verteidigen. Wer das schafft kommt mit der
                                    erspielten Summe ins Finale. Die Finalteilnehmer spielen dann
                                    zusammen gegen den Profi.</div>
                              </div>
                     </div>
                  </div>   
               </div>                  
         </li>         

Vielen Dank im Voraus  :)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 19 Juni 2020, 22:26:31
Ich kenne mich mit FTUI leider so gar nicht aus, aber kann es sein, das man sich hier eine komplett eigene Ansicht basteln müsste, die sich nur aus den Readings des DOIFs bedient? So eine Seite sollte auch nicht so schwer sein. Letztendlich ist es eine einfache Tabelle, in der jeweils einige Readings aus dem DOIF angezeigt werden. Ansonsten verstehe ich nicht weshalb dein Beispiel klappt und meine Zeile in FTUI nichts machen soll. Für mich sieht es erst mal gleich aus.

Vielleicht könntest du mir auch einfach mal eine Beispielseite erstellen, wo das DOIF eingebettet ist, dann kann ich mir das selbst in FTUI ansehen. Die Example Seite habe ich schon lange in FHEM drin, war nur immer zu faul mich damit eingehender zu beschäftigen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 20 Juni 2020, 16:37:42
Hallo mumpitzstuff,

ich habe mal eine Seite für Dich gebaut, damit Du das Popup testen kannst:

<!DOCTYPE html>
<html>
<head></head>
<body>
<div class="page" id="1_test-content">
    <div class="gridster">
        <ul>
         
            <li data-row="1" data-col="1" data-sizex="3" data-sizey="2"> <!-- Senderliste Logos -->
                <header>Senderliste</header>
                <div class="sheet">
                    <div class="cell">
    <div data-type="push" data-cmd="set" data-device="irblaster" data-set="send" data-set-on="IR_SAT_DasErste" data-background-icon="" data-icon="" class="inline senderliste" style="background-image: url('img/sender/ard.png') ;"></div>
<div data-type="push" data-cmd="set" data-device="irblaster" data-set="send" data-set-on="IR_SAT_ZDF" data-background-icon="" data-icon="" class="inline senderliste" style="background-image: url('img/sender/zdf.png') ;"></div>
<div data-type="push" data-cmd="set" data-device="irblaster" data-set="send" data-set-on="IR_SAT_RTL" data-background-icon="" data-icon="" class="inline senderliste" style="background-image: url('img/sender/rtl.png') ;"></div>
<div data-type="push" data-cmd="set" data-device="irblaster" data-set="send" data-set-on="IR_SAT_ARTE" data-background-icon="" data-icon="" class="inline senderliste" style="background-image: url('img/sender/arte.png') ;"></div>
</div>
    </div>
</li>
                   

<li data-row="1" data-col="4" data-sizex="3" data-sizey="2">
<header>Popup</header>

<div class="sheet">
<div class="cell">
<div data-type="popup"
data-height="500px"
data-width="500px"
>

<div>Hier klicken um Popup zu öffnen</div>
<div class="dialog">
<header>Popup</header>
<div>Inhalt des Popups<br>
Gefragt - Gejagt<br>
Details<br>
(2020)<br>

Moderator Alexander Bommes begrüsst in jeder Ausgabe vier
Kandidaten. In der ersten Runde werden den Kandidaten einzeln
Fragen gestellt. Für jede richtige Antwort erhält man 500 Euro.
Das erspielte Geld muss jeder Kandidat zunächst einzeln gegen
einen Quizprofi verteidigen. Wer das schafft kommt mit der
erspielten Summe ins Finale. Die Finalteilnehmer spielen dann
zusammen gegen den Profi.</div>
</div>
</div>
</div>
</div>
</li>



<li data-row="3" data-col="1" data-sizex="10" data-sizey="16">
<header>EPG Programm</header>
<div class="sheet">
<div class="row">
<div class="cell">
<div data-type="readingsgroup" data-device="doif_TEST"></div>
</div>
</div>
</div>
</li>

</ul>

</div>


</div>

</body>
</html>



In der Zelle "Popup" habe ich mal einen Mustertext für ein Popup gebaut, der funktioniert.
In der Zelle "EPG-Programm" habe ich Deine geänderte Zeile im Attribut uiTable die noch nicht funktioniert eingebaut. 

Die Zelle "Senderliste" enthält funktionierende "push" Buttons, die meinen Sat-Receiver per IR-Blaser umschalten.
Hier sind die Senderlogos schön als Button mit Hintergrund und passender Größe formatiert. Diese Liste möchte ich gerne in die erste Spalte Deines Fernsehprogramm DOIF einbauen.
Ich finde nur kein Muster für ein "push" mit uiTable. (siehe Post #77)
Falls ich noch was beisteuern kann bitte melden.   
 
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 21 Juni 2020, 02:08:52
Ich fange erst einmal damit an, das Umschalten deines Receivers zu implementieren. Kannst du bitte versuchen, den Inhalt der uiTable im doif_TEST durch das Folgende zu ersetzen? Wenn du dort schon Änderungen vorgenommen hast, dann sichere dir vorher unbedingt den Inhalt!!!

{
  package ui_Table;

  $SHOWNOSTATE = 1;
  $ATTRIBUTESFIRST = 1;
 
  $TR{0,31} = "style='color:yellow;text-align:center;font-weight:bold;font-size:18px'";
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;border-right-style:solid;border-color:#CCCCCC;border-right-width:1px;'";
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;border-color:#CCCCCC;border-right-width:1px;'";
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;'";
  $TD{30}{0..6} = "style='border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;'";

  sub showIcon
  {
    my ($icon, $device, $state) = @_;
   
    if (defined($device) && defined($state) && ('' ne $device) && ('' ne $state))
    {
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";
    }
    else
    {
      return ICON("tv/$icon");
    }
  }
 
  sub unfold
  {
    my ($title, $desc) = @_;
   
    $title = 'na' if (!defined($title));
    $desc = 'na'."\n\n".'na' if (!defined($desc));
   
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;
    $desc =~ s/<br>/\n/g;
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;
    $desc =~ s/[\r\'\"]/ /g;
    $desc =~ s/[\n]|\\n/<br>/g;

    return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>";
  }
}

# parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)
DEF TPL_TV(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))

"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"
TPL_TV($SELF,next,ARD,ard,TEST,IR_SAT-DasErste)
TPL_TV($SELF,next,ZDF,zdf,TEST,IR_SAT-DasZweite)
TPL_TV($SELF,next,Sat1,sat1)
TPL_TV($SELF,next,RTL,rtl)
TPL_TV($SELF,next,RTL2,rtl2)
TPL_TV($SELF,next,Pro7,pro7)
TPL_TV($SELF,next,DMax,dmax)
TPL_TV($SELF,next,Vox,vox)
TPL_TV($SELF,next,Kabel,kabel1)
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)
TPL_TV($SELF,next,13thStreet,13thstreet)
TPL_TV($SELF,next,Silverline,silverline)
TPL_TV($SELF,next,TNTFilm,tntfilm)
TPL_TV($SELF,next,AXN,axn)
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)
TPL_TV($SELF,next,Kinowelt,kinowelt)
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)
TPL_TV($SELF,next,Sixx,sixx)
TPL_TV($SELF,next,TNTSerie,tntserie)
TPL_TV($SELF,next,SciFi,syfy)
TPL_TV($SELF,next,ntv,ntv)
TPL_TV($SELF,next,N24Doku,n24)
TPL_TV($SELF,next,History,history)
TPL_TV($SELF,next,PLANET,planet)
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)
TPL_TV($SELF,next,AnimalPlanet,animalplanet)
TPL_TV($SELF,next,NatGeoHD,natgeo)
TPL_TV($SELF,next,TLC,tlc)
TPL_TV($SELF,next,AandE,ae)
"&nbsp;"|"&nbsp;"|"&nbsp;"|"&nbsp;"|"&nbsp;"|"&nbsp;"|"&nbsp;"
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"
TPL_TV($SELF,prime,ARD,ard)
TPL_TV($SELF,prime,ZDF,zdf)
TPL_TV($SELF,prime,Sat1,sat1)
TPL_TV($SELF,prime,RTL,rtl)
TPL_TV($SELF,prime,RTL2,rtl2)
TPL_TV($SELF,prime,Pro7,pro7)
TPL_TV($SELF,prime,DMax,dmax)
TPL_TV($SELF,prime,Vox,vox)
TPL_TV($SELF,prime,Kabel,kabel1)
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)
TPL_TV($SELF,prime,13thStreet,13thstreet)
TPL_TV($SELF,prime,Silverline,silverline)
TPL_TV($SELF,prime,TNTFilm,tntfilm)
TPL_TV($SELF,prime,AXN,axn)
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)
TPL_TV($SELF,prime,Kinowelt,kinowelt)
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)
TPL_TV($SELF,prime,Sixx,sixx)
TPL_TV($SELF,prime,TNTSerie,tntserie)
TPL_TV($SELF,prime,SciFi,syfy)
TPL_TV($SELF,prime,ntv,ntv)
TPL_TV($SELF,prime,N24Doku,n24)
TPL_TV($SELF,prime,History,history)
TPL_TV($SELF,prime,PLANET,planet)
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)
TPL_TV($SELF,prime,NatGeoHD,natgeo)
TPL_TV($SELF,prime,TLC,tlc)
TPL_TV($SELF,prime,AandE,ae)


TPL_TV($SELF,next,ARD,ard,TEST,IR_SAT-DasErste)
TPL_TV($SELF,next,ZDF,zdf,TEST,IR_SAT-DasZweite)


In den zwei Zeilen siehst du das Beispiel das ich verwendet habe. TEST ist bei mir ein dummy Device, das musst du durch dein ir blaster Device ersetzen und dahinter das entsprechende Kommando auf das state gesetzt werden soll. Bei mir kann ich jedenfalls damit auf das ARD und ZDF Icon klicken und in meinem Dummy wird der State entsprechend gesetzt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 21 Juni 2020, 13:12:32
Hallo mumpitzstuff,

vielen Dank,

habe kurz getestet, das geht aber erst morgen weiter!

ich habe "send" in den neuen Parameter mit aufgenommen, dann klappt es aus FHEM perfekt.
Damit kann ich gut leben! 


"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"
TPL_TV($SELF,next,ARD,ard,irblaster,send IR_SAT_DasErste)
TPL_TV($SELF,next,RTL,rtl,irblaster,send IR_SAT_RTL)
($SELF,prime,AandE,ae)


In FTUI springt der Browser auf die FHEM Seite:
http://xxx.yyy.zz.xy:8083/fhem?fw_id= 
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 22 Juni 2020, 01:21:32
Ich habe aktuell keine Möglichkeit gefunden aus dem DOIF heraus festzustellen, ob das DOIF über FHEMWEB oder FTUI angezeigt wird. Damit steht und fällt aber alles in Hinsicht auf FTUI. Am Ende wird es vermutlich darauf hinauslaufen, das du die uiTable nur in FHEMWEB verwenden kannst und dir aus den Readings eine komplett eigene Anzeige für FTUI basteln musst. So schwierig sollte das ja eigentlich nicht sein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: amenomade am 22 Juni 2020, 01:38:22
Zitat von: mumpitzstuff am 22 Juni 2020, 01:21:32
Ich habe aktuell keine Möglichkeit gefunden aus dem DOIF heraus festzustellen, ob das DOIF über FHEMWEB oder FTUI angezeigt wird.
Das kann nicht gehen, da FTUI eigentlich FHEMWEB mittels jsonlist2 und inform verbunden ist. Für FHEMWEB ist so zu sagen FTUI nur ein zusätzlicher Benutzer.

Zitat von: mumpitzstuff am 22 Juni 2020, 01:21:32
Damit steht und fällt aber alles in Hinsicht auf FTUI. Am Ende wird es vermutlich darauf hinauslaufen, das du die uiTable nur in FHEMWEB verwenden kannst und dir aus den Readings eine komplett eigene Anzeige für FTUI basteln musst. So schwierig sollte das ja eigentlich nicht sein.
Ja, so ist es, es sei denn, jemand entwickelt ein Widget für DOIFs mit uiTables. Aber die Komplexität von uiTables ist so hoch, dass vermutlich niemand es versuchen wird.
Fazit... wer das in FTUI will, muss eine FTUI Html Seite selbst bauen.

Was vielleicht möglich wäre: vom DOIF eine Datei mit passendem Code für FTUI generieren lassen, so dass der Benutzer nur ein copy/paste noch braucht. Das ist aber auch grosse Aufwand.



Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 22 Juni 2020, 08:56:06
Ah vielen Dank für die Klärung, dann kann ich mir weitere Sucherei ersparen!
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 22 Juni 2020, 11:57:35
uiTable hatte ursprünglich TabletUI als Schnittstelle drin, funktionierte aber nicht zuverlässig, deswegen ist sie wieder rausgeflogen: siehe: https://forum.fhem.de/index.php/topic,77690.msg729851.html#msg729851
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 22 Juni 2020, 14:25:06
Hallo zusammen,

Vielen Dank für Eure Mühe und die schnelle Hilfe.

Schade daß es keine Lösung für FTUI gibt, zumal die Darstellung als Readingsgroup out of the BOX funktioniert, bis auf die Popups mit den Detailinfos und dem Umschalten.  :'(

Um aus den Readings eine eigene FTUI-Anzeige zu bauen bin ich leider zu doof.  :)

Das Fernsehprogramm macht sich in FTUI nämlich sehr gut.

Vielleicht hat ja noch jemand Lust das zu bauen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Ellert am 22 Juni 2020, 20:22:06
ZitatSchade daß es keine Lösung für FTUI gibt, zumal die Darstellung als Readingsgroup out of the BOX funktioniert, bis auf die Popups mit den Detailinfos und dem Umschalten. 
Das FTUI Readingsgroup-Widget funktioniert in gleicher Weise mit DOIF.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Juni 2020, 22:14:48
Zitat von: robishawn am 22 Juni 2020, 14:25:06
Hallo zusammen,

Vielen Dank für Eure Mühe und die schnelle Hilfe.

Schade daß es keine Lösung für FTUI gibt, zumal die Darstellung als Readingsgroup out of the BOX funktioniert, bis auf die Popups mit den Detailinfos und dem Umschalten.  :'(

Um aus den Readings eine eigene FTUI-Anzeige zu bauen bin ich leider zu doof.  :)

Das Fernsehprogramm macht sich in FTUI nämlich sehr gut.

Vielleicht hat ja noch jemand Lust das zu bauen.

Ellert hat mir noch einen Tipp gegeben, der dich vielleicht weiter bringt. Du könntest mal versuchen dir ein separates FHEMWEB Device anzulegen. Hier stellst du einfach alles ab. Menüs, Input Zeile usw. usw. Wenn du jetzt das TV DOIF als einziges Device in einen separaten Raum legst, dann kannst du dir das defaultRoom Attribut setzen. Danach wird dir über einen bestimmten Port eine Seite NUR mit dem TV DOIF gerendert. Diese Seite könntest du dann als iframe in deine FTUI Umgebung einbetten und alles sollte funktionieren.

Hier mal ein Beispiel für die FHEMWEB Instanz (ich habe einfach mal WEBphone missbraucht, das ich vorher noch nie verwendet habe und das auf Port 8084 zu finden ist (mein doif befindet sich im Raum TEST):

defmod WEBphone FHEMWEB 8084 global
attr WEBphone Css body,input,select,textarea { font-family:Arial, sans-serif;; font-size:16px;;}\
body.touch a { font-size: 16px;; }\
body.touch #menu { font-size: 16px;; } /* for the menuTree icon */\
td {padding-left: 6px;; padding-right: 6px;; padding-top: 3px;; padding-bottom: 3px;;}\
input[type="submit"] { background-color: #353535;; border-style:outset;; border-width:2px }
attr WEBphone defaultRoom TEST
attr WEBphone styleData {\
"f18": {\
  "Pinned.menu": "true",\
  "hidePin": "true",\
  "cols.bg": "444444",\
  "cols.fg": "CCCCCC",\
  "cols.link": "a5becc",\
  "cols.evenrow": "333333",\
  "cols.oddrow": "111111",\
  "cols.header": "222222",\
  "cols.menu": "111111",\
  "cols.sel": "333333",\
  "cols.inpBack": "444444",\
  "savePinChanges": true,\
  "hideLogo": true,\
  "hideInput": true,\
  "hideTextInput": true,\
  "hideMenu": true\
}\
}
attr WEBphone stylesheetPrefix f18


Willst du das am Layout anpassen, dann setzt du einfach in deiner normalen WEB Instanz für die WEBphone Instanz hideMenu wieder auf false und speicherst ab. Dann ist das Menü wieder in deiner WEBphone Instanz sichtbar.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Juni 2020, 23:41:49
Im ersten Beitrag habe ich ein separates Template für ein set command bei Klick auf das Programmlogo hinzugefügt. Die Erklärung dazu ist unter Punkt 5 zu finden. Hiermit kann aus FHEM heraus der Sender direkt umgeschaltet werden, wenn ein entsprechendes Device dazu existiert (z.B. irblaster).
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: robishawn am 24 Juni 2020, 14:32:14
Hallo mumpitzstuff,

ich habe versucht nochmal ein neues Device anzulegen um die aktuelle Version zu nutzen, bekomme aber die Fehlermeldung :

doif_TV_Programm DOIF: no right bracket: {\ use utf8;\ use Date::Parse;\ #use Time::Piece;\ # sudo apt-get install libxml-bare-perl\ use XML::Bare 0.53 qw(forcearray);\ use Blocking;\ #use Encode qw(encode_utf8 decode_utf8);\ \


Da hat sich wohl ein Tippfehler eingeschlichen.

Den Tipp mit dem separaten FHEMWEB Device habe ich noch nicht probiert.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 24 Juni 2020, 19:32:50
Ich habs noch mal rein kopiert, konnte aber auch keinen Fehler sehen. Bei mir konnte ich das Gerät genau so anlegen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 25 Juni 2020, 21:49:45
Im ersten Beitrag habe ich mal ein ganz simples Beispiel für FTUI dran gehangen. Hübsch machen muss das jeder bitte selbst.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 25 Juni 2020, 22:11:16
Das DOIF aus dem ersten Beitrag wurde um folgende Dinge erweitert:

1.) Die Angabe eines Telnet Ports ist jetzt optional. Wenn einer angegeben ist, dann wird dieser als Backup verwendet, falls das automatische Erstellen des Ports schief geht. Ansonsten wird selbst einer erstellt und verwendet.

2.) Next und Prime initialisieren sich jetzt zeitversetzt. Zuerst wird ein Download ausgeführt, 5min später wird Next aktualisiert und 10min später Prime. Dadurch bleibt die Tabelle nicht teilweise bis zum nächsten Tag leer.

3.) Der Download wird nur noch ausgeführt, wenn die Datei nicht vorhanden oder mindestens älter als 1 Tag ist. Damit soll Download spamming vermieden werden, wenn man am Anfang noch viel an den Sendern editiert.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: fhemfreund am 29 Juni 2020, 19:10:20
Habe mal das DOIF probiert ... es funktioniert soweit und EPG Daten bekomme ich angezeigt. Allerdings bekomme ich folgende Fehlermeldung in der Senderspalte für alle Sender:


error Undefined subroutine &ui_Table::ICON called at (eval 334352) line 23. in expression: showIcon("<Sendername>",undef,undef)


Müssen in jedem Fall doch SenderLogos installiert werden?

Update: habe mal testweise das ard logo kopiert - Fehler ist immer noch da ...

Andreas
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 29 Juni 2020, 19:38:32
Zitat von: fhemfreund am 29 Juni 2020, 19:10:20
Habe mal das DOIF probiert ... es funktioniert soweit und EPG Daten bekomme ich angezeigt. Allerdings bekomme ich folgende Fehlermeldung in der Senderspalte für alle Sender:


error Undefined subroutine &ui_Table::ICON called at (eval 334352) line 23. in expression: showIcon("<Sendername>",undef,undef)


Müssen in jedem Fall doch SenderLogos installiert werden?

Update: habe mal testweise das ard logo kopiert - Fehler ist immer noch da ...

Andreas

Du musst dein DOIF updaten
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: fhemfreund am 29 Juni 2020, 20:35:57
Danke für den Tip - geht jetzt.

Andreas
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 01 Juli 2020, 10:21:33
Die neuen Features hier: https://forum.fhem.de/index.php/topic,112566.msg1069005.html#msg1069005 könnten bei dieser Aufgabe interessant sein. Z. Zt. müssen beim Fernsehprogramm Änderung sowohl im DEF-Bereich als auch im uiTable-Attribut vorgenommen werden. Eleganter wäre es Anpassungen nur an einer Stelle vornehmen zu müssen, statt an zwei.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 01 Juli 2020, 10:57:58
Okay danke. Schau ich mir an.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 03 Juli 2020, 18:42:59
Im letzten Update das DOIF hatte sich leider ein Bug eingeschlichen, der dazu führt, das der Download gar nicht mehr ausgeführt wird. Deshalb wurde der erste Beitrag entsprechend angepasst und enthält nun den Bugfix.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 14 Juli 2020, 12:08:37
Zitat von: Damian am 01 Juli 2020, 10:21:33
Die neuen Features hier: https://forum.fhem.de/index.php/topic,112566.msg1069005.html#msg1069005 könnten bei dieser Aufgabe interessant sein. Z. Zt. müssen beim Fernsehprogramm Änderung sowohl im DEF-Bereich als auch im uiTable-Attribut vorgenommen werden. Eleganter wäre es Anpassungen nur an einer Stelle vornehmen zu müssen, statt an zwei.

Ich habe es mir übrigens angesehen und würde erst einmal darauf verzichten das zu übernehmen und zwar aus folgenden Gründen:

1.) Für diesen Anwendungsfall sehe ich keinen essentiellen Mehrwert. Lediglich die Formatierungen von TD könnte man generieren lassen und der Anwender müsste dann nicht mehr manuell daran rum fummeln.
2.) Die Generierung der Templates würde in den sub Bereich rein wandern, der aktuell aber ohnehin schon recht groß ist. Die schöne Trennung zwischen Code für die Ansicht und Code zum generieren der Readings würde verloren gehen.
3.) Der Code ist, meiner Meinung nach, für nicht Programmierer nicht mehr lesbar und damit auch nicht mehr einfach vom Anwender anpassbar bzw. erweiterbar. Es ist mit Sicherheit ein mächtiges Werkzeug, ein Großteil der Anwender wird damit aber massiv überfordert sein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 14 Juli 2020, 12:19:26
Zitat von: mumpitzstuff am 14 Juli 2020, 12:08:37
Ich habe es mir übrigens angesehen und würde erst einmal darauf verzichten das zu übernehmen und zwar aus folgenden Gründen:

1.) Für diesen Anwendungsfall sehe ich keinen essentiellen Mehrwert. Lediglich die Formatierungen von TD könnte man generieren lassen und der Anwender müsste dann nicht mehr manuell daran rum fummeln.
2.) Die Generierung der Templates würde in den sub Bereich rein wandern, der aktuell aber ohnehin schon recht groß ist. Die schöne Trennung zwischen Code für die Ansicht und Code zum generieren der Readings würde verloren gehen.
3.) Der Code ist, meiner Meinung nach, für nicht Programmierer nicht mehr lesbar und damit auch nicht mehr einfach vom Anwender anpassbar bzw. erweiterbar. Es ist mit Sicherheit ein mächtiges Werkzeug, ein Großteil der Anwender wird damit aber massiv überfordert sein.

klar, man muss immer schauen, wo es sinnvoll anwendbar ist
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 15 Juli 2020, 21:30:23
Seit heute erhalte ich eine Fehlermeldung. Ich dachte, ich hätte vielleicht etwas falsch gemacht und versaut und habe deshalb mal den Code neu eingefügt. Der Fehler bleibt aber in beiden Versionen, also in meiner alten Version und in der Version hier aus dem Forum, auch wenn nichts geändert wird.

Die Fehlermeldung lautet:
error Bareword "prime" not allowed while "strict subs" in use at (eval 36221) line 1. in expression: mode (next or prime)

Kannst du mal einen Blick werfen? Ist das bei euch auch so, oder nur bei mir?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Juli 2020, 22:10:20
Nachdem ich ein Update von FHEM gemacht habe, gibt es bei mir das selbe Problem. Das muss ein Bug im DOIF Modul sein.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 16 Juli 2020, 12:17:33
Problem ist identifiziert und ich behebe es heute Abend. Alternativ kannst du auch lokal bei dir in der uiTable alle Kommentare mit 2 # versehen anstatt nur einem. Also ## anstatt #.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 16 Juli 2020, 14:04:24
Habe ich gemacht, funktioniert. War nur eine Stelle. Danke dir.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 18 August 2020, 20:08:00
Es gelingt mir nicht, das Programm in den Flooplan zu übernehmen. Über den Namen des Doif klappt es nicht. Wer sagt mir, wie es geht?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Ellert am 19 August 2020, 17:33:21
Zitat von: Invers am 18 August 2020, 20:08:00
Es gelingt mir nicht, das Programm in den Flooplan zu übernehmen. Über den Namen des Doif klappt es nicht. Wer sagt mir, wie es geht?
Das DOIF als weblink anlegen und diesen in den Floorplan einbunden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Ellert am 19 August 2020, 17:41:46
Allerdings kann ein Grundriss auch in die uiTable eingebunden werden und darauf die Schaltelemente usw. positioniert werden, https://wiki.fhem.de/wiki/DOIF/uiTable#Frontendelemente_.C3.BCber_einem_Hintergrund_.28Grundriss.29_platzieren
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 19 August 2020, 20:09:11
Danke, Ellert.
Für den 2. Vorschlag ist es zu spät, da ich schon Vieles im Flurplan angelegt habe und daher diesen beibehalten möchte.

Könntest du mir bitte den Code für den Weblink geben? Ich habe keine Ahnung, wie das geht. Mein altes Klack war html Weblink

mein letzter Versuch erzeugt nur eine leere Box.
defmod WL_KalckTV weblink htmlCode { '<a href="/fhem/floorplan/Klack"><img src="doif_TEST" width="800" height="600" ></a>' }


Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Ellert am 21 August 2020, 12:08:35
Hier hat Damian ein Beispiel angegeben http://forum.fhem.de/index.php/topic,81576.0.html
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Invers am 21 August 2020, 13:54:20
Danke dir, hat im Prinzip fuinktioniert. Den Rest habe ich dort angefragt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Tommy82 am 27 September 2020, 20:03:13
Zitat von: mumpitzstuff am 12 Juni 2020, 21:47:48
Ich habe mich mal hingesetzt und ein DOIF generiert, das die aktuellen Fernsehdaten einer Woche als xml von einem Server lädt (das DOIF macht das 1x alle 3-4 Tage) und daraus eine Programmzeitschrift generiert. Sowohl der Download als auch die Generierung geschehen non blocking. Es werden 2 Dinge generiert. Zum Einen die nächsten 3 Sendungen ab jetzt und zum Anderen die 3 Sendungen ab 20:15 Uhr. Die einzelnen Sendungen sind anklickbar und zeigen dann eine detaillierte Beschreibung zu der Sendung.

Nachdem das DOIF erstellt wurde, dauert es 5min bis die aktuellen Sendungen sichtbar werden. Die Prime Sendungen sind nach weiteren 5 Minuten sichtbar. Wenn die Prime Sendungen zwischen 20:15 Uhr und 0:00 aktualisiert werden, dann laufen sie quasi mit, da keine veralteten Sendungen angezeigt werden. Erst nach 0:30 werden dann die wirklichen Prime Sendungen des nächsten Tages (20:15 Uhr Sendungen) angezeigt.

Es gibt genau eine Vorbedingung, damit das DOIF funktioniert (alle Dinge ab 2. sind optional).

1.) XML::Bare muss mind. in der Version 0.53 installiert sein. Das kann man z.B. hiermit erledigen:

sudo apt-get install libxml-bare-perl

2.) Will man sich die Senderlogos anzeigen lassen, dann muss das Verzeichnis "/opt/fhem/www/images/default/tv" erstellt und die Rechte so gesetzt sein, das FHEM darauf zugreifen kann. Danach muss man die Senderlogos als PNGs in dieses Verzeichnis kopieren und ebenfalls die entsprechenden Rechte setzen. Die Dateien müssen die richtigen Namen besitzen! Diese kann man in der ersten Spalte der Darstellung sehen. Steht hier zum Beispiel "tv/ard" dann muss die Datei "/opt/fhem/www/images/default/tv/ard.png" heissen. Eine Quelle dafür ist z.B. (meine Logos kann ich leider aus rechtlichen Gründen hier nicht zur Verfügung stellen, aber höflich per PM fragen funktioniert vielleicht...):

https://github.com/3PO/Senderlogos/archive/master.zip (https://github.com/3PO/Senderlogos/archive/master.zip)

https://github.com/picons/picons/archive/master.zip (https://github.com/picons/picons/archive/master.zip)

https://de.wikipedia.org/wiki/Liste_deutschsprachiger_Fernsehsender (https://de.wikipedia.org/wiki/Liste_deutschsprachiger_Fernsehsender)

SVG Logos gibt es z.B. hier (habe ich noch nie verwendet, sollte aber auch gehen):

https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de (https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de)

Ansonsten gibt es diverse Programmezeitschriften online, bei denen man sich die Bilder der Sender runterladen kann.

3.) Wenn man Sender hinzufügen möchte, dann kann man sich die original xml Dateien runterladen und die entsprechenden Sender raus suchen.

http://rytecepg.dyndns.tv/epg_data/ (http://rytecepg.dyndns.tv/epg_data/)

Danach muss man folgende Dinge anpassen (wenn man einen Sender entfernen möchte, muss man die entsprechenden Dinge ebenfalls anpassen):
a) Die Variable $_channelFilter.
b) Im Attribut uiTable muss man 2 Zeilen hinzufügen: "TPL_TV($SELF,next,<sender name>,<logo name>)" und weiter unten "TPL_TV($SELF,prime,<sender name>,<logo name>)"
c) Danach muss man noch die Formatierung ebenfalls im Attribut uiTable anpassen. Diese beginnen mit $TR und $TD.

Die xml Daten stellen jede Menge weiterer Sender zur Verfügung.

Unten habe ich auch mal ein Testscript dl.pl angehangen, womit man seinen channelfilter erst einmal überprüfen kann. Einfach den channelfilter im Script anpassen und ausführen und man sieht das Ergebnis erst einmal in einer Testdatei und kann, wenn alles funktioniert, das Regex ins DOIF übertragen. Es ist wichtig, das man immer den Text aus der id nimmt!

<channel id="ARD.de">

4.) Es stehen 2 Templates zur Verfügung. TPL_TV wird normalerweise verwendet und stellt das Programmlogo und 3 Sendezeiten dar. Darüber hinaus kann auch TPL_TVSET verwendet werden. Hier kann durch ein Klick auf das Programmlogo ein set Befehl an ein beliebiges FHEM Device geschickt werden, um z.B. den Fernsehsender aus FHEM heraus zu wechseln.

Beispiel:
TPL_TV($SELF,next,ARD,ard)
kann ersetzt werden durch:
TPL_TVSET($SELF,next,ARD,ard,irblasterdevice,send IR_SAT_DasErste)

5.) Wenn man andere Sender oder mehr als die vorhandenen haben möchte, kann man z.B. hier sehen was es sonst noch alles gibt:

http://rytecepg.dyndns.tv/epg_data/ (http://rytecepg.dyndns.tv/epg_data/)

Im DOIF werden nur die beiden Dateien rytecDE_Basic.xz und rytecDE_Common.xz geladen und gemerged. Das bdedeutet, das man aktuell nur Sender aus diesen beiden Dateien anzeigen lassen kann. Es gibt aber die Möglichkeit weitere Dateien zu mergen und dann ebenfalls anzeigen zu lassen wie z.B. rytecDE_SportMovies.xz.

Dazu muss man einfach die Funktion "sub tvDownloadMerge()" suchen und diese ersetzen:

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');

    # download and merge other files here if needed
   
    return $output;
  }


durch

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_SportMovies.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_SportMovies.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');
    tvMerge($_dataFile, $_path.'rytecDE_SportMovies');

    # download and merge other files here if needed
   
    return $output;
  }


ersetzen. Das Spiel lässt sich beliebig fortsetzen.


defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem/';;\
  $_dataFile = $_path.'rytecDE_Basic';;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
  \
  \
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
  \
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
  \
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs) \
    { \
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
    \
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
    \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        if ((0 != $_filterChannels) ||\
            ($_->{'channel'}{'value'} =~ $_channelFilter))\
        {\
          my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
          # filter old stuff\
          if ($stop > $old)\
          {\
            if ($lastChannel ne $_->{'channel'}{'value'})\
            {\
              $lastChannel = $_->{'channel'}{'value'};;\
              $reading = $_->{'channel'}{'value'};;\
              $reading =~ s/[\.\s]//g;;\
              $reading =~ s/de$//;;\
              $n = 0;;\
               \
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
              {\
                $i = 0;;\
\
                if (0 != $_updateBasedOnStarttimes)\
                {\
                  $_startTimes{$reading} = $stop;;\
                }\
              }\
              else\
              {\
                ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
              }\
            }\
\
            if ($i < 3 && 'next' eq $mode)\
            {\
              my $fi = sprintf("%03d", $i);;\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $i++;;\
            }\
\
            if ($n < 3 && 'prime' eq $mode)\
            {\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $fmtStart = FmtDateTime($start);;\
              my $bdate = substr($fmtStart, 0, 10);;\
              my $btime = substr($fmtStart, 11, 8);;\
\
              if ($bdate.' '.$btime gt $primeTime)\
              {\
                my $fn = sprintf("%03d", $n);;\
                my $readingName;;\
                my $readingValue;;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
                $readingValue = substr(FmtDateTime($start), 0, 10);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
                $readingValue = substr(FmtDateTime($start), 11, 8);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
                if (exists($_->{'sub-title'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'sub-title'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
                if (exists($_->{'desc'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'desc'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $k++;;\
                $n++;;\
              }\
            }\
\
            if ($k >= 10)\
            {\
              #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
              \
              `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
              \
              $k = 0;;\
              $sendTelnet = '';;\
            }\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
  \
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
    \
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);;\
    \
    tvMerge($_dataFile, $_path.'rytecDE_Common');;\
\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
    \
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    # prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      \
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
  \
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    \
    $output = tvDownloadMerge();;\
    \
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
  \
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
  \
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
  \
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
  \
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
        \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
  \
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:15])\
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST room TEST
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  \
  $TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{0..6} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
    \
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,ARD,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,Pro7,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,Kabel,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,ARD,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,Pro7,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,Kabel,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)


Hi,
entweder hab ich was überlesen oder stehe mir auf dem schlauch, was genau muss ich machen um das zu nutzen? die XML::Bare hab ich installiert und die Senderlogos ins entsprechende Fhem verzeichniss kopiert. Und jetzt?

Danke
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 28 September 2020, 01:53:32
Du öffnest einfach ein beliebiges Device und scrollst ganz nach unten und klickst auf raw Definition. Dort löschst du alles was drin steht und kopierst die gesamte Definition (das letzte das mit defmod anfängt aus dem ersten Beitrag) dort rein und klickst dann auf execute commands. Fertig.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 05 November 2020, 14:05:00
Hallo,

habe mir gerade das tolle DOIF installiert und es funktioniert erst mal. Danke für die tolle Arbeit.

Allerdings scheitere ich daran, einen neuen Sender hinzuzufügen: ORF1 (testweise)
Der wäre in der Datei "rytecAT_Basic".
Also habe ich in der Funktion tvDownloadMerge die folgenden Zeilen hinzugefügt:
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecAT_Basic.xz -O /opt/fhem/rytecAT_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecAT_Basic.xz 2>&1);

    tvMerge($_dataFile, $_path.'rytecDE_Common');
    tvMerge($_dataFile, $_path.'rytecAT_Basic');


Kann es sein, dass da in der Anleitung ein kleiner Fehler ist? Wieso wird "rytecDE_Common" als "rytecDE_SportMovies.xz" abgespeichert?
Da steht nämlich:
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_SportMovies.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_SportMovies.xz 2>&1);


Die Datei "rytecAT_Basic" ist auch im Verzeichnis "/opt/fhem" zu finden.
Da steht für ORF1 folgendes drinnen:
  <channel id="ORF1.at">
    <display-name lang="en">ORF eins</display-name>
  </channel>


Also habe ich im Attribut "uiTable" in den "TPL_TV"-Blöcken folgenden Eintrag hinzugefügt:
TPL_TV($SELF,next,ORF1,orf1)
und
TPL_TV($SELF,prime,ORF1,orf1)

Es erscheinen nun zwei Zeilen mit dem richtigen Logo, aber es kommen keine Programm-Einträge.
Die Spalten sind immer leer.
Die anderen Spalten sind sehr wohl befüllt.

Was mache ich falsch?

Danke für jede Hilfe.
lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 05 November 2020, 15:06:46
Das Mergen ist richtig wie es scheint. In der Beschreibung ist tatsächlich ein kleiner Fehler drin (habe ich korrigiert). Ich hatte das nur schnell im Editor angepasst ohne das zu prüfen.

Soweit ich sehe hast du vergessen die Variable $_channelFilter anzupassen. Wenn hier nicht bereits der gewünschte Sender eingefügt wird, dann wird dieser bereits beim mergen raus geschmissen und wird niemals in deinem Programm auftauchen.

In deinem Fall müsste das dann so etwa aussehen:

$_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.|ORF1\.)/;;\

Danach musst du erst einmal den Download wieder ausführen. Am einfachsten geht das wenn du alle rytec Dateien löschst und dann fhem mit shutdown reload restartest.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 06 November 2020, 11:05:41
Hallo,

Vielen Dank für Deine Hilfe.
Ich hatte doch glatt vergessen, dass mit dem $_channelFilter zu erwähnen.
Den neuen Kanal ORF1 habe ich dort ebenfalls hinzugegeben.
Zur Sicherheit habe ich also Deine Liste kopiert, alles gespeichert, die 3 Dateien gelöscht und fhem neu gestartet.
Die 3 Spalten beim ORF sind aber immer noch leer.

Also habe ich das Device gelöscht und alles neu angelegt.
Hilft aber auch nix, die 3 Spalten bei ORF 1 und dann auch ORF2 sind leer, obwohl alles andere angezeigt wird.

Kann man irgendwie debug-Ausgaben bekommen?
Verbose bzw. Logging höher zu setzen, bringt leider nix.

Danke!
Lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 06 November 2020, 11:34:48
Das eigenartige ist, dass die entsprechenden readings sehr wohl vorhanden sind und auch stimmen.
Es gibt also die next_ORF1at und prime_ORF1at

Wieso heißen die aber ORF1at und nicht so wie beim ARD?
Wenn ich die Bezeichnung ORF1at im uiTable verwende, dann erscheinen die Einträge in den Spalten.

Lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 06 November 2020, 13:40:08
Hmm ich filtere .de automatisch raus wie es scheint. Das habe ich ganz vergessen. Da ich bisher nur .de Sender verwendet hatte, ist mir das gar nicht mehr aufgefallen.
Im DOIF kannst du aber diese Zeile:
$reading =~ s/de$/;
durch das ersetzen:
$reading =~ s/(de|at)$/;

Dann würde at ebenfalls gefiltert werden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 07 November 2020, 10:44:26
Hallo,

ich glaube, ich lasse es mal, so wie es ist (außer Du gibst eine neue offizielle Version heraus ;))
Danke auf alle Fälle.

Nun wollte ich das Ganze natürlich um ORF2, ATV, ServusTV etc. ergänzen.
Die Spalten und die Logos sind auch in der Übersicht, aber halt wieder kein Text.
Da ich keinerlei Fehlermeldungen bekomme, habe ich mich mit dem dl.pl gespielt.

Die Sender erscheinen dort auch und in der Test-Datei "rytecDE_Basic.test" sind auch alle EPG-Einträge.
Trotzdem erscheinen bei den neuen Sendern keine Einträge in der Übersicht, beim ORF1 schon - komisch.

Hast Du vielleicht noch einen Tipp?

Danke, lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 07 November 2020, 14:15:28
Schau zuerst mal ob die entsprechenden Readings erzeugt wurden. Ist das der Fall? Falls nicht, dann wurde entweder der Download nach deinen Änderungen nicht angestoßen oder dein Regex ist falsch. Falls sie vorhanden sind, wie genau sehen die Readings aus und wie deine TPL_TV Aufrufe im Skript?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 08 November 2020, 11:00:49
Hallo,

Danke für die Tipps.
Es wurden alle verfügbaren Sender als Readings angelegt.
Nachdem ich einfach nicht mehr weitergekommen bin, habe ich mal testweise Deine Änderung bzgl. de|at eingebaut.
Nach ein paar restarts und den notwendigen Änderungen in dem uiTable sind nun die Einträge da.
Nur für ServusTV noch nicht. Das muss ich mir noch anschauen.
Ganz schön zickig das Teil  ;)
Vor allem weil keinerlei Debug-Info via logging rauskommt.

Ein Thema habe ich aber noch:
In der Übersicht sind die Formatierungen für die Zeilen verschoben.
Auffällig ist das vor allem, weil die Überschrift für Prime ohne jede Formatierung angezeigt wird.
Und mitten im EGP-Block ist dann auf einmal eine Zeile gelb und fett.

Danke im Voraus
Lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 08 November 2020, 16:41:32
Hallo nochmal,

nun verzweifle ich an den Logos.
Ich hätte nicht gedacht, dass sich dieses Thema als so zickig und aufwändig herausstellt.

Mein grundsätzliches Problem ist, dass in der Übersicht die Logos zu groß sind.
Kann man die Größe irgendwo einstellen?

1) https://github.com/3PO/Senderlogos/archive/master.zip (https://github.com/3PO/Senderlogos/archive/master.zip) die sind zu groß
2) https://github.com/picons/picons/archive/master.zip (https://github.com/picons/picons/archive/master.zip) die pngs sind zu groß; aber zuerst das svg von ORF1 getestet, klappt.
    Also alle weiteren runtergeladen und eingespielt -> die klappen nicht mehr :(
3) https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de (https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de) die svgs werden bei mir in fhem nicht angezeigt.

die von Klack.de (http://klack.de) sind leider auch viel zu groß.

Es ist echt zum Verzweifeln.
Wieso kann fhem die SVGs von z.B. Wikipedia nicht darstellen?

Zur Zeit sieht meine Übersicht so wie im Anhang aus (zumindest ein Teil davon).

lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 09 November 2020, 01:32:22
Zuerst einmal kriegst du das mit der Formatierung hin, indem du 3c beachtest. Man muss die Stellen mit $TD und $TR entsprechend anpassen. Die Logos musst du vereinheitlichen. Mit anderen Worten du musst dir eine Größe definieren und alle Logos auf diese Größe skalieren.

Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: gestein am 09 November 2020, 11:39:50
Hallo,
vielen Dank für die Hinweise.
Mit 3c hatte ich bis dato gar nichts zu tun.
Aber der Tipp mit $TR und $TD hat mir geholfen.
Durch herumprobieren habe ich nun die Formatierungen richtig.
D.h., jedesmal wenn man einen Sender dazu gibt bzw. wegnimmt, muss man auch das ändern.
Kommt ja nur am Anfang häufig vor, dann eher nicht mehr.

Bei den Logos scheint es also am Einfachsten zu sein, wenn man die PNGs per Gimp kleiner macht.
Schade, dass man die Größe nicht als Parameter übergeben kann und dass das Funktion automatisch macht.
Aber auch das sollte sich händisch machen lassen.

Vielen Dank nochmals für Deine Hilfe!
lg, Gerhard
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 09 November 2020, 16:57:40
Bei den Logos könnte man eventuell versuchen eine feste Größe für die Tabellenzelle per css vorzugeben (die $TD und $TR Angaben). Eventuell wird dadurch der Browser die Logos selbstständig skalieren (habe ich nie probiert), was insbesondere bei svg Dateien gut funktionieren müsste.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: en-trust am 11 Dezember 2020, 12:12:59
wie beschrieben, habe ich testweise mal die Logos für ARD (das erste.png) und ZDF (zdf.png) nach /opt/fhem/www/images/default/tv kopiert und das doif angepasst.

TPL_TV($SELF,next,ARD,das erste)
TPL_TV($SELF,next,ZDF,zdf)


aber weder ARD noch ZDF werden angezeigt. Rechte auf tv Verzeichnis stehen sogar auf 777 und fhem.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 11 Dezember 2020, 19:50:09
Mir ist nicht ganz klar was nicht angezeigt wird. Das Fernsehprogramm, die Icons oder Beides?

Bei der Datei müssen die Rechte/Owner in etwa so gesetzt sein:

-rw-r--r-- 1 fhem dialout  1662 Jun 17 02:32 ard.png


Und beim Verzeichnis tv so:

drwxr-xr-x 2 fhem dialout  4096 Jun 17 01:12 tv
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: en-trust am 14 Dezember 2020, 07:12:48
Lag tatsächlich an den Rechten, die ich zwar schon gesetzt hatte, vermutlich aber noch nicht im System angekommen sind.

Um die Icons nicht fix zu skalieren, wäre es natürlich besser, diese in fhem flexible zu skalieren. Daher die Frage, an welcher Stelle diese vorgesehen ist. Ich vermute hier....

return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";

  sub showIcon
  {
    my ($icon, $device, $state) = @_;
   
    if (defined($device) && defined($state))
    {
      return "<div style=\"height : 50px;\"><a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a></div>";
    }
    else
    {
      return ICON("tv/$icon");
    }
  }
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 14 Dezember 2020, 22:07:52
Dort bist du an der richtigen Stelle. Es gibt hier mit Sicherheit Dinge, die man dort besser machen könnte, aber den Code kann ja auch jeder frei anpassen und ist somit auf diese Art flexibel. Mir fehlt an der Stelle ehrlich gesagt das Fachwissen über den ganzen Web Kram. Mein Wissen darüber ist auf dem Stand von vor 20 Jahren eingefroren...  ;D
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: en-trust am 15 Dezember 2020, 07:42:46
Also so ganz klappt es nicht...

    if (defined($device) && defined($state))
    {
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\"><span style=\"max-width: 80px; height: 50px;\">".ICON("tv/$icon")."</span></a>";
    }
    else
    {
      return "<span style=\"max-width: 80px; height: 50px;\">".ICON("tv/$icon")."</span>";
    }


Ich vermute das <span> Tag wird von dem <img> überbügelt.

<td align='center' style='border-right-style:solid;border-color:#CCCCCC;border-right-width:1px;' ><span style="max-width: 80px; height: 50px;"><img class=' tv/das erste' src="/fhem/images/default/tv/das%20erste.png" alt="tv/das erste" title="tv/das erste"></span></td>

Vielleicht hat ja noch jemand eine Idee.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: en-trust am 17 Dezember 2020, 15:12:15
Keiner eine Idee ?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 29 März 2021, 15:00:41
Zitat von: mumpitzstuff am 14 Juli 2020, 12:08:37
Ich habe es mir übrigens angesehen und würde erst einmal darauf verzichten das zu übernehmen und zwar aus folgenden Gründen:

1.) Für diesen Anwendungsfall sehe ich keinen essentiellen Mehrwert. Lediglich die Formatierungen von TD könnte man generieren lassen und der Anwender müsste dann nicht mehr manuell daran rum fummeln.
2.) Die Generierung der Templates würde in den sub Bereich rein wandern, der aktuell aber ohnehin schon recht groß ist. Die schöne Trennung zwischen Code für die Ansicht und Code zum generieren der Readings würde verloren gehen.
3.) Der Code ist, meiner Meinung nach, für nicht Programmierer nicht mehr lesbar und damit auch nicht mehr einfach vom Anwender anpassbar bzw. erweiterbar. Es ist mit Sicherheit ein mächtiges Werkzeug, ein Großteil der Anwender wird damit aber massiv überfordert sein.
Ich habe mich für eine Zwischenlösung entschieden: eine Variable. Weiterhin habe ich Font (TR) und Rahmen (TD) getrennt sowie den linken statt dem rechten Rahmen gesetzt.

  my $PRIMEROW = 30;
  $TR{0,31} = "style='color:yellow;text-align:center;font-weight:bold;font-size:18px'";
  $TR{1..($PRIMEROW - 1),($PRIMEROW + 2)..($PRIMEROW * 2)} = "style='font-size:16px'";
  $TR{$PRIMEROW} = "style='border-top-style:solid;border-bottom-style:solid;border-color:#CCCCCC;border-top-width:1px;border-bottom-width:1px;'";
  $TD{0..($PRIMEROW * 2)}{0} = "align='center'";
  $TD{0..($PRIMEROW - 1),($PRIMEROW + 1)..($PRIMEROW * 2)}{1,3,5} = "style='border-left-style:solid;border-color:#CCCCCC;border-left-width:1px;'";

Bei der ersten Zeile geht es (bei mir?) mit der Variable nicht, keine Ahnung, warum.

Wo findet man eine Liste der möglichen Programme und deren Zuordnung zu den .xy-Files? Konkret suche ich die 3. Programme, ComedyCentral und ServusTV.de.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 30 März 2021, 10:54:30
Schau dir mal 3. im ersten Post an. Dort steht drin, das du dir die Datei originale Datei runterladen und dir dort die notwendigen Senderinfos raussuchen musst. Was die Formatierung angeht, muss ich mir das später noch mal ansehen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 31 März 2021, 11:24:25
OK, habe mal den Channel-Filter auf .* gesetzt und von Null nach meinen Wünschen aufgebaut, jetzt passt es mit den Dritten. Danke für den Tipp.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 31 März 2021, 15:02:01
Und gleich nochwas. Da ich kein webfähiges TV-Device habe, aber IPTV (HorizonGO), habe ich mir das UI angepasst. Eine neue Funktion showIconIP, eine angepasste Vorlage TPL_TVIP und ein neues Reading VIEW1 (frei vergebbar, falls man mehrere URL braucht).

sub showIconIP
{
  my ($icon, $device, $state) = @_;
 
  if (defined($device) && defined($state))
  {
    return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";
  }
  else
  {
    return ICON("tv/$icon");
  }
}

## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))

setreading doif_TEST VIEW1 https://www.horizon.tv/de_de/tv/channel-asset.html/$state/location/<eigene USER-ID>.html#action=watch

Und schon kann ich aus meinem Browser direkt das Programm aufrufen.
Achja, Syntax im uiTable:
TPL_TVIP($SELF,next,ZDF,zdf,VIEW1,29438503164)
VIEW1 ist der selbstgewählte Readingname für die URL (quasi beliebig viele möglich), 29438503164 ist die ID des Providers für (hier) ZDF-HD.

Da ich jetzt "betriebsblind" bin, stellt Fragen, falls was unklar ist oder ich was vergessen habe!

PS: geht sogar ohne weitere Änderung auf dem (Android-)Handy mit der App...
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: JudgeDredd am 24 August 2021, 19:17:24
Hallo Zusammen,

ich habe gestern mal begonnen das TV-Programm zu integrieren.
Soweit erstmal kein Problem.

Allerdings habe ich gestern beim Einrichten die EPG Dateien von hier geholt:
http://www.vuplus-community.net/rytec/rytecDE_Common.xz
http://www.vuplus-community.net/rytec/rytecDE_Basic.xz


Heute als ich weitermachen wollte, ist die Quelle schon versiegt.

Frage:
Ist das jetzt purer Zufall, oder kommt es häufiger vor, das man die Quelle wechseln muss ?

Gruß,
JudgeDredd
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 24 August 2021, 20:05:32
Das scheint ein dummer Zufall zu sein. Ich habe diese Quelle seit vielen Monaten verwendet.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: JudgeDredd am 25 August 2021, 10:49:16
Zitat von: mumpitzstuff am 24 August 2021, 20:05:32Das scheint ein dummer Zufall zu sein. Ich habe diese Quelle seit vielen Monaten verwendet.
Na prima, da hab ich ja mal wieder richtig Glück gehabt  :o

Dann warte ich mal ein paar Tage auf "Heilung", ansonsten muss ich mal nach einer Alternativen Quelle Ausschau halten.
Allerdings habe ich festgestellt, das sich die gleichen EPG-Dateien bei unterschiedlicher Quelle trotzdem minimal bei den enthaltenen Sendern unterscheiden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: JudgeDredd am 27 August 2021, 11:50:49
Zitat von: JudgeDredd am 25 August 2021, 10:49:16
Dann warte ich mal ein paar Tage auf "Heilung", ansonsten muss ich mal nach einer Alternativen Quelle Ausschau halten.
Allerdings habe ich festgestellt, das sich die gleichen EPG-Dateien bei unterschiedlicher Quelle trotzdem minimal bei den enthaltenen Sendern unterscheiden.
Falls hier noch jemand mitliest, nur zur Info:
die Quelle sprudelt wieder  :D
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: slupus am 26 November 2021, 21:08:07
Für alle die nach einer funktionierenden Quelle suchen:
http://www.xmltvepg.nl/rytecDE_Basic.xz

Die überall erwähnte Quelle scheint versiegt:
http://www.vuplus-community.net/rytec/rytecDE_Basic.xz
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: JudgeDredd am 26 November 2021, 21:21:10
Zitat von: slupus am 26 November 2021, 21:08:07
Die überall erwähnte Quelle scheint versiegt:
http://www.vuplus-community.net/rytec/rytecDE_Basic.xz
Die Quelle ist nur umgezogen auf:
http://epg.vuplus-community.net/rytecDE_Basic.xz
http://epg.vuplus-community.net/rytecDE_Common.xz
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 14 Dezember 2022, 21:15:48
Zwei Fragen:
1. wäre es nicht sinnvoll, die Quelle als attr zu hinterlegen? Dann können die vielen # aus dem Code raus und er ist schnell angepasst, wenn der Server mal wieder wechselt.
2. kann man channelfilter nicht aus den TPL nehmen/erstellen? Ist dann nicht der kürzeste/effektivste Code, aber viel leichter zu warten. Und sooo oft wird diese Funktion nicht aufgerufen, dass es den dramatischen Performanceeinbruch geben wird.

Ersteres traue ich mir noch selbst zu, ich will aber keinen Fork aufmachen. Fürs zweite fehlt mir der Durchblick im Code.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Dezember 2022, 00:14:14
1. Klar. Das kann man tun. Bisher war das aber relativ stabil. Bei mir läuft das Ganze reibungslos seit vielen Monaten. Deshalb habe ich da nicht so viel Wert darauf gelegt. Du kannst aber den Code gern anpassen und posten, dann kann ich das im ersten Beitrag übernehmen.

2. Ich glaube nicht, dass das wirklich irgendwie funktioniert bzw. dann gäbe es zu viele Abhängigkeiten und Kompromisse, selbst wenn man das dort irgendwie raus lösen könnte. Das macht für mich wenig Sinn und hat wenig bis keinen Mehrwert. Eventuell kann man aber den Filter ebenfalls als Attribut aufnehmen, um auch hier einfacher Änderungen vornehmen zu können.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 15 Dezember 2022, 16:44:54
Meine Änderungen:

Zusätzliche Attribute
attr TV_Programm userattr Server
attr TV_Programm Server http://epg.vuplus-community.net


Änderung der Subs
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    $output .= qx(wget $_Server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_Server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\

...tvDownloadMerge ebenso, Rest wie gehabt

Änderung des Initialteils der Subs:
  $_Server = AttrVal("$SELF","Server","");; \

Nicht dabei ist ein Abfangen, wenn kein attr gesetzt ist, war es aber vorher (falscher Server oder so) auch nur nicht.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: dyna am 15 Dezember 2022, 19:14:59
Moin mumpitzstuff,

gibt es eine einfache Möglichkeit die List in FTUI2 / FUIP einzubinden?

Viele Grüße
Jens
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Dezember 2022, 21:01:35
Zitat von: dyna am 15 Dezember 2022, 19:14:59
Moin mumpitzstuff,

gibt es eine einfache Möglichkeit die List in FTUI2 / FUIP einzubinden?

Viele Grüße
Jens

Im ersten Beitrag hatte ich mal was ganz ganz einfaches gestrickt für FTUI und als zip dort abgelegt. Ich kenne mich damit aber so gar nicht aus und das nicht weiter verfolgt bzw. verbessert oder verschönert.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Dezember 2022, 21:02:55
@Per Ich schau mir das nächste Woche an (da habe ich dann Urlaub) und aktualisiere den Beitrag. Vielen Dank!
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 15 Dezember 2022, 23:00:36
Dann spiele ich bis dahin noch etwas rum :D

Z.B. eine Variante mit nur einer Liste, welche dann fürs aktuelle und fürs Prime 2x durchlaufen wird.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 16 Dezember 2022, 01:56:55
Wenn man weiß, wie es geht, ist es gar nicht sooo schwer. Aber die Syntax war, aufgrund des Fhem-Perl-ui-Mix, viel trail'n'error.
Ist jetzt reduziert auf ein Minimum, außer den Ausgaben des aktullen Wertes zum Verständnis. Mit besseren RegEx Kenntnissen (die gehen bei mir gegen Null, aber von unten ;)) wäre es sinnvoll, den Eintrag erst zu löschen (ersetzen mit ""), wenn er schon vorhaben ist und dann zu adden. Dürfte schneller gehen als zu testen, ob er vorhanden ist und dann zu übergehen.

defmod TV_Test DOIF ##
attr TV_Test uiTable
{\
package ui_Table;;\
\
sub add\
{\
my ($wert) = @_;;\
$_Senderliste .= $wert . "\\.|";;\
return $wert;;\
}\
}\
\
DEF TPL_TV(add ("$3")|$_Senderliste)\
\
$_Senderliste = "";;"SL=$_Senderliste"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
::fhem("setreading $SELF Sender " . $_Senderliste);;"SL=$_Senderliste"


Als Nächstes schreibe ich dir Unfold um, damit die Syntax der TPL leichter wird...

Tante Edit meint, ich solle es in die Senderlogo Sub einbauen. Mache ich doch glatt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 16 Dezember 2022, 15:59:34
Soooo, sehr langes Ooooo.

Prinzipiell bin ich "fertig".
Was geht:
- die Senderliste wird erstellt und als Reading abgelegt.
- die Senderliste wird eingelesen und das qr erstellt.
- die TPL sind vereinfacht (Unfold aufgebohrt).
- Server für die rytech-Files als attr.

Was nicht geht:
- die Filterliste filtert nicht. Ich bekomme Unmengen Readings von nicht ausgewählten Sendern. Sie geht aber auch nicht, wenn ich die fest vorgebe.
- sind keine rytech-Files da, geht der Rechner in die Knie. Den Fall hatte ich nebenbei, weil der letzte gepostete Server (epg.vuplus-community.net) nicht wollte. *)

Beim Ersten spiele ich mal noch etwas rum **), bei letzteren habe ich keine Idee, wo mal das abfangen muss.

*) im normalen Betrieb sollte das nicht passieren, da ich die Dateien aber gelöscht hatte, war kein Backup für das Script da. Inzwischen weiss ich, dass ich diese Files fürs Testen der Filter nicht löschen muss.

**) Noch gar nicht abgeschickt und schon festgestellt: das ist mir zu hoch! Ich bin mir aber sicher, dass ich die überflüssigen Readings früher auch schon hatte, bevor ich an der Filter-Automatik rumgespielt hatte. Zum Vergleich habe ich mir nen jungfräulichen Code von Seite 1 gezogen: Bingo, dort geht der Filter auch nicht (zumindest nicht so, wie ich ihn erwarte). Damit warte ich auf die Reaktion eines RegEx-Native-Speakers ;)

PS: ich hänge den aktuellen Stand trotzdem mal an, der Filter/Reading wird erstellt, aber nicht genutzt.

defmod TV_Programm DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  my $channelFilter = ReadingsVal("$SELF","Sender","ZDF\.");;\
  $channelFilter =~ s/\|$//;;\
  $_channelFilter_channelFilter = qr/^(?:$channelFilter)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem/';;\
  $_dataFile = $_path.'rytecDE_Basic';;\
  $_Server = AttrVal("$SELF","Server","");; \
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
  \
  \
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
  \
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
  \
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs) \
    { \
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
    \
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
    \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        if ((0 != $_filterChannels) ||\
            ($_->{'channel'}{'value'} =~ $_channelFilter))\
        {\
          my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
          # filter old stuff\
          if ($stop > $old)\
          {\
            if ($lastChannel ne $_->{'channel'}{'value'})\
            {\
              $lastChannel = $_->{'channel'}{'value'};;\
              $reading = $_->{'channel'}{'value'};;\
              $reading =~ s/[\.\s]//g;;\
              $reading =~ s/de$//;;\
              $n = 0;;\
               \
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
              {\
                $i = 0;;\
\
                if (0 != $_updateBasedOnStarttimes)\
                {\
                  $_startTimes{$reading} = $stop;;\
                }\
              }\
              else\
              {\
                ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
              }\
            }\
\
            if ($i < 3 && 'next' eq $mode)\
            {\
              my $fi = sprintf("%03d", $i);;\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $i++;;\
            }\
\
            if ($n < 3 && 'prime' eq $mode)\
            {\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $fmtStart = FmtDateTime($start);;\
              my $bdate = substr($fmtStart, 0, 10);;\
              my $btime = substr($fmtStart, 11, 8);;\
\
              if ($bdate.' '.$btime gt $primeTime)\
              {\
                my $fn = sprintf("%03d", $n);;\
                my $readingName;;\
                my $readingValue;;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
                $readingValue = substr(FmtDateTime($start), 0, 10);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
                $readingValue = substr(FmtDateTime($start), 11, 8);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
                if (exists($_->{'sub-title'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'sub-title'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
                if (exists($_->{'desc'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'desc'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $k++;;\
                $n++;;\
              }\
            }\
\
            if ($k >= 10)\
            {\
              #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
              \
              `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
              \
              $k = 0;;\
              $sendTelnet = '';;\
            }\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
  \
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    $output .= qx(wget $_Server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_Server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
    \
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';; \
    \
    $output .= qx(wget $_Server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_Server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    tvMerge($_dataFile, $_path.'rytecDE_Common');;\
\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
    \
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    # prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      \
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
    \
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
   \
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
  \
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    \
    $output = tvDownloadMerge();;\
    \
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
  \
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
  \
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
  \
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
  \
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
        \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
  \
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:01])\
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}

attr TV_Programm userattr Server
attr TV_Programm Server http://epg.vuplus-community.net
attr TV_Programm alias Aktuelles TV-Programm

attr TV_Programm uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  my $PRIMEROW = 39;;\
\
  $TR{0,40} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TR{1..($PRIMEROW - 1),($PRIMEROW + 2)..($PRIMEROW * 2)} = "style='font-size:16px'";;\
  $TR{$PRIMEROW} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
  $TD{0..($PRIMEROW * 2)}{0} = "align='center'";;\
  $TD{0..($PRIMEROW - 1),($PRIMEROW + 1)..($PRIMEROW * 2)}{1,3,5} = "style='border-left-style:solid;;border-color:#CCCCCC;;border-left-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $show, $device, $state) = @_;;\
    $_Senderliste =~ s/$icon\\.\|//;;\
    $_Senderliste .= $icon . "\\.|";;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("$show");;\
    }\
  }\
  \
  sub showIconIP\
  {\
    my ($icon, $show, $device, $state) = @_;;\
    $_Senderliste =~ s/$icon\\.\|//;;\
    $_Senderliste .= $icon . "\\.|";;\
\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("$show")."</a>";;\
    }\
    else\
    {\
      return ICON("$show");;\
    }\
  }\
  sub unfold\
  {\
    my ($ReadingPre) = @_;;\
    my $title = ::ReadingsVal("$SELF","${ReadingPre}_title","-");;\
    my $desc = ::ReadingsVal("$SELF","${ReadingPre}_stitle","na")."\n\n". ::ReadingsVal("$SELF","${ReadingPre}_desc","na") ;;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
     return substr(::ReadingsVal("$SELF","${ReadingPre}_btime",""),0,5) . \
            "</td><td><a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$2","$3",undef,undef)|unfold("$1_$2_000")|unfold("$1_$2_001")|unfold("$1_$2_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$2","$3","$4","$5")|unfold("$1_$2_000")|unfold("$1_$2_001")|unfold("$1_$2_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVIP(showIconIP("$2","$3","$4","$5")|unfold("$1_$2_000")|unfold("$1_$2_001")|unfold("$1_$2_002"))\
\
$_Senderliste = "";;"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Naechste Sendung"|"ab"|"Sendung"\
TPL_TVIP(next,DasErste,01 ARD,VIEW1,29438503040)\
TPL_TV(next,HGTV,428 HGTV)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV(prime,DasErste,ard)\
TPL_TV(prime,ZDF,zdf)\
TPL_TV(prime,History,history)\
TPL_TV(prime,TLC,tlc)\
::fhem("setreading $SELF Sender $_Senderliste");;

Da ist die von mir geeänderte Optik der Tabelle (Farben) und der Zugriff auf IP-TV noch drin, lasse ich jetzt auch so.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 16 Dezember 2022, 17:36:58
Ich glaube löschen und dann einfügen ist sehr viel teurer als zu testen ob etwas da ist. Die Filterliste hängt von deinem Server ab. Leider unterscheiden sich die Ausgaben der Server und die Filterliste muss unter Umständen angepasst werden. Da du dir die aktuell zusammen setzt, müsstest du mir mal deinen aktuellen Filter posten, dann kann ich dir sagen, was daran falsch ist.

Privat verwende ich z.b. folgenden Server mit folgendem Filter:

http://www.xmltvepg.nl/rytecDE_Basic.xz
http://www.xmltvepg.nl/rytecDE_Common.xz

$_channelFilter = qr/^(?:DasErste\.|ZDF\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;

Der Filter hängt somit vom Server ab. Deshalb ist es wie gesagt auch keine gute Idee das so zu mchen, wie du es planst. Als Attribut abzulegen in Ordnung (wobei ds bei den ganzen Sonderzeichen eventuell auch Probleme macht) aber aus den Sendernamen das Ganze rauszuholen macht keinen Sinn. Wenn man mal den Server ändern muss, müsste man auch seine Sendernamen anpassen und eventuell auch die Namen der Icons. Das ist halt schon irgendwie suboptimal. Außerdem gibt es halt eventuell Besonderheiten zu beachten, die du mit einem zusammen gebastelten Regex nicht abbilden kannst.

Siehe dazu im direkten Vergleich:

http://epg.vuplus-community.net/rytecDE_Basic.xz
http://epg.vuplus-community.net/rytecDE_Common.xz

$_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\


Um deinen Filter zu testen kannst du folgendes tun:

1.) download der Dateien vom verwendeten Server und entpacken
2.) die seite https://regex101.com/ öffnen und aus allen runtergeladenen entpackten dateien alle channel tags (sind immer am anfang dr datei) in die regex seite bei TEST STRING einfügen (einfach hintereinander wenns mehrere Dateien sind)
3.) alles was bei channelFilter zwischen qr/<kopiere mich>/ steht kopieren und bei REGULAR EXPRESSION eintragen und ganz vorn das ^ zeichen durch " ersetzen

Und Schwups kannst du sehen was alles matcht und was nicht.



https://regex101.com/
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 16 Dezember 2022, 18:52:45
Prinzipiell gebe ich dir Recht, was fehlerhafte Filter angeht, ich habe für mich dein Muster aus Beitrag 1 angepasst. ABER: Schon dein Filter aus Beitrag 1 mit dem original Download (vor ca. 2 Stunden) zeigt das Ergebnis, dass nicht gefiltert wird. Waru weiß ich natürlich nicht, dafür kenne ich mich damit zu wenig aus. Aber ich brauche meinen Filter nicht anzupassen, wenn es mit deinem schon nicht geht.

Ansonsten wird meiner aus dem TPLs in der Form erstellt, wie deiner auch aussieht, nur halt jeder Sender einzeln. Und das Ergebnis ist halt auch das Gleiche: jeder Sender wird geparsed.

Und ja, wenn sich was ändert (ARD -> DasErste, Pro7 -> ProSieben) müssen die TPL eh angepasst werden, aber nicht TPL UND Filter. Und wenn aus Pro(7|SiebenMaxx) -> ProSieben( :o |Maxx) wird, bin wahrscheinlich nicht nur ich überfordert. Hatte mir mit ProSiebe(n|nMaxx) geholfen, aber jeden einzeln sollte ja auch funktionieren.

Und um deine Frage zu beantworten:
VOXup\.|3sat\.|ARTE\.|ServusHD\.|NDRFernsehen\.|WDRFernsehen\.|HRFernsehen\.|SWRFernsehen\.|MDRS-Anhalt\.|BRFernsehen\.|ComedyCentralVIVA\.|SuperRTL\.|RTLNitro\.|Tele5\.|Sat1Gold\.|phoenix\.|ZDFinfo\.|Sport1HD\.|Eurosport1\.|WELT\.|tagesschau24\.|MotorVision\.|HGTV\.|DasErste\.|ZDF\.|Sat1\.|RTL\.|RTL2\.|ProSieben\.|DMax\.|Vox\.|KabelEins\.|KabelEinsDoku\.|KabelEinsClassic\.|ProSiebenMaxx\.|Sixx\.|ntv\.|N24Doku\.|History\.|TLC\.|

Dazu dann die am Anfang der Subs
  my $channelFilter = ReadingsVal("$SELF","Sender","ZDF\.");
  $channelFilter =~ s/\|$//;
  $_channelFilter_channelFilter = qr/^(?:$channelFilter)/;


Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 16 Dezember 2022, 19:17:46
Den Filter den ich verwende filtert mit Sicherheit (ich habe genau nur die Readings, die ich auch haben möchte im Device) und deshalb auch der aus dem Originalbeitrag, da bin ich mir ebenfalls sicher. Es wird zuerst beim Download die Dateigröße reduziert (vorgefiltert) und dann bei den Readings passiert das noch einmal. An einer Stelle könnte man sich das wahrscheinlich schenken. Den Filter kann man oben in der Config Area aber deaktivieren.

Im Anhang sieht man das direkt. Die 2 Dateien die ich merge, haben zusammen normal über 20MB. Durch den Filter aber keine 4MB mehr.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 16 Dezember 2022, 23:45:31
Wie gesagt, ich kann es von der Programmierung nicht nachvollziehen. Nur nochmal soviel: den Code von Post 1 kopiert und ausgeführt, ohne irgendwelche Änderungen, ergab trotzdem die Unmengen Readings. Somit kann ich am Filter machen was ich will, es ändert sich nichts an den Readings.


Außer ich mache nen Syntaxfehler und Fhem gibt Fehler aus.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 17 Dezember 2022, 17:28:34
Du hast auch alle existierenden Readings vorher gelöscht? Hast du dir mal die Datei angesehen bzw. die Größe der Datendatei? Wenn man die beiden Standard Dateien ohne Filter mergen würde, müsste die Datei 20+MB umfassen. Sobald der Filter wirkt, ist sie wesentlich kleiner.
Zudem ist es ein Unterschied ob gar nichts gefiltert wird oder nicht alles rausgefiltert wird, was du erwarten würdest. Eventuell werden noch zu viele Sender durch das Regex durchgelassen.

Ich habe deine Änderungen bei mir mal lokal übernommen und beobachte mal das Verhalten. Die Änderungen an der Unfold Funktion habe ich erst einmal außen vor gelassen, das war mir im Moment zu heikel. Btw deine Layout Änderungen habe ich auch noch nicht übernommen. Könntest du mir bitte einen kleinen Screenshot schicken, um zu sehen, ob ich das gut finden würde? Die Tests laufen aber noch ein wenig, da ich mal einen vollen Zyklus durchlaufen lassen möchte.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 17 Dezember 2022, 22:15:28
Mein Test sieht aktuell so aus:

defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  ## sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:DasErste\.|ZDF\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  $_channelFilterNew = AttrVal("$SELF", "channelFilter", "^(?:DasErste\.|ZDF\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)");;\
  $_channelFilterNew = qr/$_channelFilterNew/;;\
  ## telnet port must not be password protected (open)\
  ## this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  ## can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem';;\
  $_dataFile = $_path.'/rytecDE_Basic';;\
  $_server = AttrVal("$SELF", "server", "http://www.xmltvepg.nl");;\
  ## enable/disable unused channel filtering on filemerge (enabled = small file and less readings = faster)\
  $_filterChannels = 1;;\
  ## enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  ## enable/disable use of Time::Piece (timepiece is faster but not installed on some systems)\
  $_timepiece = 0;;\
\
  ## internal variables\
  $_startTimes = ();;\
\
\
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    ##$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
\
      ## fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      ## slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
\
    foreach my $d (sort keys %::defs) \
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
\
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
\
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
\
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
\
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
\
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
        ## filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
\
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
\
          if ($i < 3 && 'next' eq $mode)\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $readingName;;\
            my $readingValue;;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
            $readingValue = substr(FmtDateTime($start), 0, 10);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
            $readingValue = substr(FmtDateTime($start), 11, 8);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
            if (exists($_->{'sub-title'}{'value'}))\
            {\
              $readingValue = filterText($_->{'sub-title'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
            if (exists($_->{'desc'}{'value'}))\
            {\
              $readingValue = filterText($_->{'desc'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $k++;;\
            $i++;;\
          }\
\
          if ($n < 3 && 'prime' eq $mode)\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
\
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $n++;;\
            }\
          }\
\
          if ($k >= 10)\
          {\
            ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
\
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
\
    return %{$_startTimes};;\
  }\
\
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilterNew)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilterNew)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilterNew)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilterNew)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';;\
\
    ## other server see below\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
\
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl/rytecDE_Basic.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_Basic.xz\
    ## http://epg.vuplus-community.net/rytecDE_Basic.xz\
    ## http://www.xmltvepg.nl/rytecDE_Common.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_Common.xz\
    ## http://epg.vuplus-community.net/rytecDE_Common.xz\
    ## http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
\
    ## download and merge other files here if needed\
\
    return $output;;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
\
    ## prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
\
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
\
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
\
    $output = tvDownloadMerge();;\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
\
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
\
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
\
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
\
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
\
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
\
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_PARSE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
\
  if ([+00:15])\
  {\
    startParse("$SELF", 'next');;\
  }\
\
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST userattr server channelFilter
attr doif_TEST server http://www.xmltvepg.nl
attr doif_TEST channelFilter ^(?:DasErste\.|ZDF\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)
attr doif_TEST event-on-change-reading .*
attr doif_TEST room TV
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  $NUM_CHANNELS = 29;;\
\
  $TR{0,($NUM_CHANNELS + 2)} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..$NUM_CHANNELS,($NUM_CHANNELS + 2)..($NUM_CHANNELS + 2 + $NUM_CHANNELS)}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..$NUM_CHANNELS,($NUM_CHANNELS + 2)..($NUM_CHANNELS + 2 + $NUM_CHANNELS)}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..($NUM_CHANNELS + 2 + $NUM_CHANNELS)}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{($NUM_CHANNELS + 1)}{0..6} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
\
  sub showIconIP\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
\
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
\
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
\
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVSET($SELF,next,DasErste,ard,<ir blaster device>,<ir blaster command>)\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVIP($SELF,next,DasErste,ard,VIEW1,29438503040)\
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,DasErste,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,ProSieben,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,KabelEins,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,ProSieben,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,KabelEins,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)


Was mir aber beim rum spielen aufgefallen ist, ist das die Attribute nicht übernommen werden, wenn man die bei RAW Definition einfügt. Die muss man immer manuell nachziehen, was irgendwie recht beschissen ist, da man dann die ganzen doppelten Semikolons und Backslashes manuell vorher entfernen muss.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: MadMax-FHEM am 17 Dezember 2022, 22:36:28
Ist wohl ein "generelles" Problem: https://forum.fhem.de/index.php/topic,131002.msg1252056.html#msg1252056

Gruß, Joachim
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 18 Dezember 2022, 19:39:36
Meine Güte, was für ein blöder Fehler, aus $_channelFilter wurde irgendwann mal $_channelFilter_channelFilter. Und dann filtert natürlich nichts mehr.
Jetzt halten sich die Readings in den gewünschten Grenzen.
Der zum Test geladene Code hat mit den bereits runtergeladenen Files gearbeitet, deshalb hat der auch nichts gefiltert.
Jetzt läuft ein Test mit automatisch erstelltem Filter und der scheint zu klappen. Zumindest beim Neustart. Wobei beim Erweitern des Filters nix passiert, wahrscheinlich weil das Alter der Datei kleiner 1 Tag ist. Also morgen um die gleiche Zeit ein Update.

Und falls alles nicht funktioniert, bekommt man wenigstens bequem die Liste zum Einfügen :D

Zitat von: MadMax-FHEM am 17 Dezember 2022, 22:36:28
Ist wohl ein "generelles" Problem: https://forum.fhem.de/index.php/topic,131002.msg1252056.html#msg1252056
Schau mal, wer den Thread eröffnet hat ;)

Zitat von: mumpitzstuff am 17 Dezember 2022, 22:15:28Was mir aber beim rum spielen aufgefallen ist, ist das die Attribute nicht übernommen werden, wenn man die bei RAW Definition einfügt.
Könnte daran liegen, dass das UserAttr eine Gedenksekunde braucht, um angelegt zu werden. Versuch es mal ein zweites Mal, ob es dann klappt.

Wichtig: "Server" ist alphabetisch vor "userattr", da muss man beim row-Export drauf achten.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: MadMax-FHEM am 18 Dezember 2022, 19:54:35
Zitat von: Per am 18 Dezember 2022, 19:39:36
Schau mal, wer den Thread eröffnet hat ;)

Ja, hatte ich dann auch bemerkt ;)

Gruß, Joachim
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 18 Dezember 2022, 20:14:46
Wenn es morgen die rytecDE_Basic sauber aktualisiert, würde ich noch folgende Änderungen vorschlagen/einpflegen:
- deletereading $SELF (next|prime)_.* 200000
- Readings nach Channel_mode_XXX erstellen
- title -> 1title, stitle -> 2stitle, desc -> 3desc. Wegen der Lesbarkeit möchte mein innerer Monk das so ;)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 18 Dezember 2022, 23:27:46
Deletereading ist sehr ungünstig denke ich, weil dann erst alles verschwindet und alle Reading danach neu befüllt werden müssen. Bei langsamen Systemen dauert das eine Weile und dann ist die ReadingGroup erst leer und wird neu befüllt. Und sowas hier, würde dann gar nicht mehr funktionieren = ewig viele Events: attr doif_TEST event-on-change-reading .*
Mit der Reihenfolge der Attribute habe ich noch etwas rum gespielt, aber irgendwie greift das nicht, egal welche Reihenfolge ich bei den Attributen verwende. Änderungen in der uiTable werden mit RAW defintion nicht übernommen. Keine Ahnung warum. Ich muss damit vielleicht noch etwas auf dem Testsystem rum spielen. Übrigens wenn das Device neu angelegt wird, dann scheint noch alles übernommen zu werden. Anders sieht es aber bei Änderungen aus. Wenn ich quasi in einem Editor das exportierte RAW ändere und dann komplett neu einspielen will, dann wird immer nur ein Teil davon übernommen.

Folgende Dinge musste ich aktuell aber schon wieder zurück bauen:

$TR{0,($NUM_CHANNELS + 2)} = ...

Aktionen wie diese funktionieren bei mir nicht. Das Format wird einfach gar nicht mehr übernommen. Vielleicht muss ich da noch mal nachfragen, weshalb das so ist.

Wenn ich ein Regex in ein Attribut schreibe und das z.B. so aussieht: ^(?:DasErste\.|ZDF\.)
Dann fliegt das \. irgendwie später raus. Ich bin mir noch nicht ganz sicher was da passiert, vermute aber, dass das \ irgendwie raus fliegt und dann z.b. ZDF ud ZDFinfo durchgelassen werden, obwohl ich nur ZDF haben möchte.

PS: Kannst du mir bitte noch ein kleines Bild deiner Layoutänderungen zukommen lassen?

Meine aktuelle Fassung sieht deshalb wieder so aus:

defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  ## sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:DasErste\.|ZDF\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  ## telnet port must not be password protected (open)\
  ## this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  ## can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem';;\
  $_dataFile = $_path.'/rytecDE_Basic';;\
  $_server = AttrVal("$SELF", "server", "http://www.xmltvepg.nl");;\
  ## enable/disable unused channel filtering on filemerge (enabled = small file and less readings = faster)\
  $_filterChannels = 1;;\
  ## enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  ## enable/disable use of Time::Piece (timepiece is faster but not installed on some systems)\
  $_timepiece = 0;;\
\
  ## internal variables\
  $_startTimes = ();;\
\
\
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    ##$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
\
      ## fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      ## slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
\
    foreach my $d (sort keys %::defs) \
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
\
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
\
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
\
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
\
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
\
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
        ## filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
\
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
\
          if ($i < 3 && 'next' eq $mode)\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $readingName;;\
            my $readingValue;;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
            $readingValue = substr(FmtDateTime($start), 0, 10);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
            $readingValue = substr(FmtDateTime($start), 11, 8);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
            if (exists($_->{'sub-title'}{'value'}))\
            {\
              $readingValue = filterText($_->{'sub-title'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
            if (exists($_->{'desc'}{'value'}))\
            {\
              $readingValue = filterText($_->{'desc'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $k++;;\
            $i++;;\
          }\
\
          if ($n < 3 && 'prime' eq $mode)\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
\
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $n++;;\
            }\
          }\
\
          if ($k >= 10)\
          {\
            ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
\
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
\
    return %{$_startTimes};;\
  }\
\
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';;\
\
    ## other server see below\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
\
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl/rytecDE_Basic.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_Basic.xz\
    ## http://epg.vuplus-community.net/rytecDE_Basic.xz\
    ## http://www.xmltvepg.nl/rytecDE_Common.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_Common.xz\
    ## http://epg.vuplus-community.net/rytecDE_Common.xz\
    ## http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    ## http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    ## http://rytecepg.epgspot.com/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
\
    ## download and merge other files here if needed\
\
    return $output;;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
\
    ## prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
\
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
\
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
\
    $output = tvDownloadMerge();;\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
\
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
\
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
\
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
\
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
\
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
\
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_PARSE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
\
  if ([+00:15])\
  {\
    startParse("$SELF", 'next');;\
  }\
\
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST userattr server
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST event-on-change-reading .*
attr doif_TEST room TV
attr doif_TEST server http://www.xmltvepg.nl
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
\
  ## 29 normal channels, 2 heading lines and 29 prime channels
  ## 31 = 29 (normal channels) + 2 (headings)
  ## 60 = 29 (normal channels) + 2 (headings) + 29 (prime channels)
  ## 30 = 29 (normal channels) + 1 (first heading)
  $TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{0..6} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
\
  sub showIconIP\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
\
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
\
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
\
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVSET($SELF,next,DasErste,ard,<ir blaster device>,<ir blaster command>)\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVIP($SELF,next,DasErste,ard,VIEW1,29438503040)\
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,DasErste,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,ProSieben,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,KabelEins,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,ProSieben,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,KabelEins,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)


Was richtig viel bringt ist übrigens das entfernen des channelFilters bei der Aktualisierung der Readings. Mein Rechner bleibt jetzt im Durchschnitt 1-2°C kühler als vorher. Der channelFilter kommt jetzt nur noch beim Download alle 3 Tage zum tragen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 19 Dezember 2022, 21:02:20
- deletereading 200000 löscht alle Readings > 2000000s (etwas mehr als 2 Tage). Die längste mir bekannte Sendung war die Live-Übertragung eines 24-Stunden-Rennens. Hatte damals aber nicht geschaut, ob das nur ein Eintrag ist. >2Tage dürfte da ausreichend Puffer sein.

- Warum gibt es in StartDownload $_channelFilter? Ich habe nichts gefunden, wohin das übergeben wird.
- tvParse und tvMerge bekomme ich nicht zum Setzen von Readings überredet. Können die das nicht, weil es im BlockingCall arbeiten?
- mein erstelltes RegEx sieht dem manuell erstelten zum Verwechseln ähnlich, zumindest die exportierten Readings. Ich kann das aber auch nur im StartDownload testen, weil tvParse und tvMerge keine Readings erstellen. Zumindest zeigen sie die mir nicht.

- Die Daten für die Formatierung ist etwas durcheinander, weil ich $_channelFilter zwischendurch nicht aktualisiert habe.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 19 Dezember 2022, 23:38:59
In startDownload gibt es doch gar keinen channelFilter. Oder übersehe ich irgendwas?
tvParse und tvMerge werden NonBlocking ausgeführt, deshalb kannst du dort keine Readings auf direktem Wege setzen. Also entweder über Telnet (so wie ich das mache) oder du musst das über die returns durchschleifen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 21 Dezember 2022, 15:19:34
Das mit dem nonBlocking fiel mir dann auch wie Schuppen von den Haaren ;)

Habe jetzt eine Variante durchgeproggt, ich poste sie, wenn sie ein paar Tage gelaufen ist. Dabei sind nicht nur alle meine bisherigen Punkte abgehakt, sie ist auch noch Multi-Device-fähig. Falls Mama was anderes ansehen will als Papa.

Allerdings werde ich den Quellcode dann nochmal komplett umsortieren. Und meinen Debugcode ausmisten.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 22 Dezember 2022, 00:38:13
So, Tests laufen weiter, aber wer schon mal reinschauen will...
defmod TV_Programm DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  $_name = "$SELF";;\
  $_path = '/opt/fhem/';;\
  $_data = 'rytecDE_filt_'.$_name;;\
  $_dataFile = $_path.$_data;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  $_server = AttrVal($_name,"server","http://epg.vuplus-community.net");; \
  my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
  $channelFilter =~ s/\|$//;;\
  $_channelFilter = qr/^(?:$channelFilter)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
\
  sub filterText($)\
  {\
    my $text = shift;;\
    \
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
    \
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
    \
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
      \
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs)\
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
      \
      $telnet = $d;;\
      last;;\
    }\
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
      \
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
      \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
    \
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
      \
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
        \
           # filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
    \
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
      \
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
  \
          if ($i < 3 && 'next' eq $mode)\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $readingName;;\
            my $readingValue;;\
    \
            $readingName = $reading.'_'.'next_'.$fi.'_1bdate';;\
            $readingValue = substr(FmtDateTime($start), 0, 10);;\
            $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
    \
            $readingName = $reading.'_'.'next_'.$fi.'_2btime';;\
            $readingValue = substr(FmtDateTime($start), 11, 8);;\
            $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
    \
            $readingName = $reading.'_'.'next_'.$fi.'_3title';;\
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
    \
            $readingName = $reading.'_'.'next_'.$fi.'_4stitle';;\
            if (exists($_->{'sub-title'}{'value'}))\
            {\
              $readingValue = filterText($_->{'sub-title'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
    \
            $readingName = $reading.'_'.'next_'.$fi.'_5desc';;\
            if (exists($_->{'desc'}{'value'}))\
            {\
              $readingValue = filterText($_->{'desc'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
    \
            $k++;;\
            $i++;;\
          }\
  \
          if ($n < 3 && 'prime' eq $mode)\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
    \
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
              my $readingName;;\
              my $readingValue;;\
      \
              $readingName = $reading.'_'.'prime_'.$fn.'_1bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
      \
              $readingName = $reading.'_'.'prime_'.$fn.'_2btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
      \
              $readingName = $reading.'_'.'prime_'.$fn.'_3title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
      \
              $readingName = $reading.'_'.'prime_'.$fn.'_4stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
      \
              $readingName = $reading.'_'.'prime_'.$fn.'_5desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device _$readingName $readingValue";;\
      \
              $k++;;\
              $n++;;\
            }\
          }\
  \
          if ($k >= 10)\
          {\
    #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
      \
      if ('' ne $sendTelnet)\
      {\
          #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
    \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub tvMerge($$$$)\
  {\
    my ($path, $dstName, $orgName, $server) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
    my $output = "";;\
    my $ftime = 2;;\
    my $srcName = $path.$orgName;;\
    $dstName = $path.$dstName;;\
    \
    if (-e $srcName)\
      {\
      $ftime = ((time() - (stat($srcName))[9]) / 60.0 / 60.0 / 24.0);;\
    }\
    if ($ftime > 1)\
    {\
        $output .= qx(wget $server/$orgName -O $srcName.xz 2>&1);;\
        $output .= qx(xz -df $srcName.xz 2>&1);;\
    }\
    \
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
    \
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
    \
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
    \
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
    \
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
        \
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
    \
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
        \
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
    \
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
          \
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
      \
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
          \
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
    \
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
      \
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
      \
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
      \
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
      \
      close($fh);;\
    }\
    return $output;;\
  }\
\
  sub tvDownloadMerge($$$$)\
  {\
    my ($name, $path, $data, $server) = @_;;\
    my $output = '';;\
    \
    $output .= qx(cp -f $path/rytecDE_leer $path/$data 2>&1);;\
    \
    $output .= tvMerge($path, $data, 'rytecDE_Basic', $server);;\
    $output .= tvMerge($path, $data, 'rytecDE_Common', $server);;\
##    $output .= tvMerge($path, $data, 'rytecDE_SportMovies.xz', $server);;\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my ($name, $path, $data, $server) = split("\\|", shift);;\
    my $output = '';;\
    \
    $output = tvDownloadMerge($name, $path, $data, $server);;\
    \
    return $name.'|'.$output;;\
  }\
\
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
    $channelFilter =~ s/\|$//;;\
    $_channelFilter = qr/^(?:$channelFilter)/;;\
    # prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $btime = ((time() - (stat($_path.'rytecDE_Basic'))[9]) / 60.0 / 60.0 / 24.0);;\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      my $rtime = (ReadingsAge($_name,"sender",3600)  / 60.0 / 60.0 / 24.0) ;;\
      \
      if ($btime < 1.0 and $ftime < 1.0 and $ftime < $rtime)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($btime).')('.($ftime).')('.($rtime).').';;\
        return;;\
      }\
    }\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
      \
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
    \
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name.'|'.$_path.'|'.$_data.'|'.$_server, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
}\
\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 480, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:01])\
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}\
renew\
  {\
  if ([$SELF:sender])\
  {\
    startDownload("$SELF");;\
    set_Exec('init_next', 30, 'startParse("$SELF", "next")');;\
    set_Exec('init_prime', 60, 'startParse("$SELF", "prime")');;\
  }\
}
attr TV_Programm alias Aktuelles TV-Programm
attr TV_Programm event-on-change-reading .*
attr TV_Programm userattr server:http://epg.vuplus-community.net,http://www.xmltvepg.nl,http://91.121.106.172/~rytecepg/epg_data,http://epg.vuplus-community.net
attr TV_Programm server http://epg.vuplus-community.net
attr TV_Programm room Wohnzimmer
attr TV_Programm uiTable\
{\
  package ui_Table;;\
  \
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  my $PRIMEROW = 39;;\
  \
  $TR{0,40} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TR{1..($PRIMEROW - 1),($PRIMEROW + 2)..($PRIMEROW * 2)} = "style='font-size:16px'";;\
  $TR{$PRIMEROW} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
  $TD{0..($PRIMEROW * 2)}{0} = "align='center'";;\
  $TD{0..($PRIMEROW - 1),($PRIMEROW + 1)..($PRIMEROW * 2)}{1,3,5} = "style='border-left-style:solid;;border-color:#CCCCCC;;border-left-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $show, $device, $state) = @_;;\
    $_Senderliste =~ s/$icon\\.\|//;;\
    $_Senderliste .= $icon . "\\.|";;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("$show");;\
    }\
  }\
\
  sub showIconIP\
  {\
    my ($icon, $show, $device, $state) = @_;;\
    $_Senderliste =~ s/$icon\\.\|//;;\
    $_Senderliste .= $icon . "\\.|";;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("$show")."</a>";;\
    }\
    else\
    {\
      return ICON("$show");;\
    }\
  }\
\
  sub unfold\
  {\
    my ($ReadingPre) = @_;;\
    my $title = ::ReadingsVal("$SELF","_${ReadingPre}_3title","-");;\
    my $desc = ::ReadingsVal("$SELF","_${ReadingPre}_4stitle","na")."\n\n". ::ReadingsVal("$SELF","_${ReadingPre}_5desc","na") ;;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
    \
    return substr(::ReadingsVal("$SELF","_${ReadingPre}_2btime",""),0,5) . \
            "</td><td><a href=\"#!\" onclick=\"FW_okDialog(';$title<br>$desc';)\">$title</a>";;\
  }\
\
  sub renewFilter()\
  {\
    if (::ReadingsVal("$SELF","sender","ZDF\\.") ne $_Senderliste)\
    {\
      ::fhem("setreading $SELF sender $_Senderliste");;\
    }\
    ::fhem("deletereading $SELF .*(next|prime)_.*  200000");;\
  }\
}\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$2","$3",undef,undef)|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$2","$3","$4","$5")|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVIP(showIconIP("$2","$3","$4","$5")|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
$_Senderliste = "";;"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Naechste Sendung"|"ab"|"Sendung"\
TPL_TVIP(next,DasErste,01 ARD,VIEW1,29438503040)\
TPL_TVIP(next,ZDF,02 ZDF,VIEW1,29438503164)\
TPL_TVIP(next,RTL,04 RTL,VIEW1,29438503175)\
TPL_TVIP(next,RTL2,05 RTL2,VIEW1,904120359445)\
TPL_TVIP(next,Vox,06 Vox,VIEW1,29438503001)\
TPL_TVIP(next,VOXup,.. VOXup,VIEW1,911733287342)\
TPL_TVIP(next,ProSieben,07 ProSieben,VIEW1,29438503097)\
TPL_TVIP(next,Sat1,08 Sat1,VIEW1,29438503126)\
TPL_TVIP(next,KabelEins,09 KabelEins,VIEW1,29438503100)\
TPL_TVIP(next,3sat,10 3Sat,VIEW1,616178215134)\
TPL_TVIP(next,ARTE,11 Arte,VIEW1,342571559048)\
TPL_TVIP(next,DMax,12 D-Max,VIEW1,29438503089)\
TPL_TVIP(next,ServusHD,13 ServusTV,VIEW1,29438502999)\
TPL_TVIP(next,NDRFernsehen,14 NDR,VIEW1,29438503143)\
TPL_TVIP(next,WDRFernsehen,15 WDR,VIEW1,761024551272)\
TPL_TVIP(next,HRFernsehen,16 HR3,VIEW1,761026599328)\
TPL_TVIP(next,SWRFernsehen,17 SWR,VIEW1,761023015389)\
TPL_TVIP(next,MDRS-Anhalt,18 MDR SA,VIEW1,834825255151)\
TPL_TVIP(next,BRFernsehen,BR3,VIEW1,29438503048)\
TPL_TVIP(next,ComedyCentralVIVA,19 CC,VIEW1,29438502952)\
TPL_TVIP(next,ProSiebenMaxx,20 pro7maxx,VIEW1,432862759167)\
TPL_TVIP(next,SuperRTL,21 SuperRTL,VIEW1,29438503124)\
TPL_TVIP(next,RTLNitro,22 Nitro,VIEW1,29438503118)\
TPL_TVIP(next,Tele5,23 Tele5,VIEW1,29609511124)\
TPL_TVIP(next,Sat1Gold,24 Sat1 Gold,VIEW1,720012839067)\
TPL_TVIP(next,phoenix,25 phoenix,VIEW1,706496551303)\
TPL_TVIP(next,KabelEinsDoku,202 Kabel1doku,VIEW1,745574951375)\
TPL_TVIP(next,N24Doku,203 n24 Doku,VIEW1,745574951376)\
TPL_TVIP(next,ZDFinfo,204 ZDF Info,VIEW1,745574951376)\
TPL_TVIP(next,Sport1HD,300 DSF,VIEW1,465354791385)\
TPL_TVIP(next,Eurosport1,301 Eurosport,VIEW1,465354791385)\
TPL_TVIP(next,WELT,302 Welt n-24,VIEW1,465354791385)\
TPL_TVIP(next,ntv,303 n-tv,VIEW1,29438503069)\
TPL_TVIP(next,tagesschau24,304 tagesschau24,VIEW1,834825255153)\
TPL_TVIP(next,TLC,TLC,VIEW1,488928807317)\
TPL_TVIP(next,Sixx,?? Sixx,VIEW1,465354791388)\
TPL_TVIP(next,MotorVision,552 MV,VIEW1,817724967007)\
TPL_TV(next,HGTV,428 HGTV,VIEW1,0)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV(prime,DasErste,ard)\
TPL_TV(prime,ZDF,zdf)\
TPL_TV(prime,Sat1,sat1)\
TPL_TV(prime,RTL,rtl)\
TPL_TV(prime,RTL2,rtl2)\
TPL_TV(prime,ProSieben,pro7)\
TPL_TV(prime,DMax,dmax)\
TPL_TV(prime,Vox,vox)\
TPL_TV(prime,KabelEins,kabel1)\
TPL_TV(prime,KabelEinsDoku,kabel1doku)\
TPL_TV(prime,KabelEinsClassic,kabel1classic)\
TPL_TV(prime,ProSiebenMaxx,pro7maxx)\
TPL_TV(prime,Sixx,sixx)\
TPL_TV(prime,ntv,ntv)\
TPL_TV(prime,N24Doku,n24)\
TPL_TV(prime,History,history)\
TPL_TV(prime,TLC,tlc)\
renewFilter();;

Natürlich wieder meine Sender und meine Formatierung ;) Und die Parameter für Unitymedia-IPTV. Ist zwar inzwischen offline, habe ich aber noch nicht gelöscht. Mal sehen, vllt. kommt da eine Verlinkung auf den jeweiligen Live-Stream hin, denn mein TV unterstützt keine Fernbedienung außer der beigelegten IR. Und eine IR für Fhem liegt zwar schon da, ist aber noch nicht installiert.
Einstellungen sind wie beim Original die TPL für next und prime am Ende, und die rytec-Dateien Zeile 495ff. Der Server kann über attr ausgewählt werden. Und wer nicht in "/opt/fhem" installiert hat, muss diese Variable im Code ändern. K.A., ob und wie das über Perl automatisch abzufragen geht.
Am Merge und am Parse habe ich, magels Verständnis außer der Reihenfolge im Code und den übergebenen Parametern (noch ;)) nichts geändert.

Achja, die Datei "rytecDE_leer" in "/opt/fhem" braucht es noch. Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<tv generator-info-name="Rytec" generator-info-url="https://forums.openpli.org" generator-info-partner="bStream-Panel">
  <channel id="XXX.de">
    <display-name lang="de">XXX</display-name>
  </channel>
  <programme start="20221220035500 +0000" stop="20221220040000 +0000" channel="XXX.de">
    <title lang="de">Platzhalter</title>
    <sub-title lang="de">Platz</sub-title>
    <desc lang="de">Platzhalter</desc>
  </programme>
</tv>

Könnte man, statt sie als Datei zu kopieren, auch aus dem Quellcode heraus erstellen, aber ersteres empfinde ich einfacher.
Statt der Datei gäbe es bestimmt noch andere Möglichkeiten ohne, aber wie gesagt, dafür komme ich zuwenig mit Parse und Merge klar.

PS: durch einen Programmierfehler (einer von hunderten :D) habe ich heute mal die ZDFneo Videothek aufgesucht...

Tante Edit sagt: pwd gibt das aktuelle Arbeitsverzeichnis zurück. Denke, das werde ich noch nachpflegen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 22 Dezember 2022, 21:28:33
Zitat von: mumpitzstuff am 18 Dezember 2022, 23:27:46
Folgende Dinge musste ich aktuell aber schon wieder zurück bauen:

$TR{0,($NUM_CHANNELS + 2)} = ...

Aktionen wie diese funktionieren bei mir nicht. Das Format wird einfach gar nicht mehr übernommen. Vielleicht muss ich da noch mal nachfragen, weshalb das so ist.
Bei mir auch nicht, deshalb hatte ich dort eine feste Zahl  {0,40} drin.
was aber geht:
$TR{0} = XXX...
$TR{($NUM_CHANNELS + 2)} = XXX...

Warum auch immer. Die Zahl habe ich jetzt auch automatisch erstellt, da sie aber erst nach einem Durchlauf erstellt wird, ist es nötig, das attr ui_Table noch ein zweites Mal zu speichern.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 23 Dezember 2022, 10:26:24
Zitat von: Per am 22 Dezember 2022, 21:28:33
Bei mir auch nicht, deshalb hatte ich dort eine feste Zahl  {0,40} drin.
was aber geht:
$TR{0} = XXX...
$TR{($NUM_CHANNELS + 2)} = XXX...

Warum auch immer. Die Zahl habe ich jetzt auch automatisch erstellt, da sie aber erst nach einem Durchlauf erstellt wird, ist es nötig, das attr ui_Table noch ein zweites Mal zu speichern.

$TR wird wie folgt abgebildet:

  $wcmd =~ s/\$TR\{/\$hash->{$table}{tr}\{/g;

Offenbar kann in Perl die Referenz keine Berechnung sein, reine Variablen sollten funktionieren.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 23 Dezember 2022, 12:51:36
In anderen Zeilen habe ich Berechnungen drin, da geht es. Als Zweizeiler kann er ja auch.
Und {0,$YYY} ging auch nicht.
Vllt mit anderen oder ohne Klammern?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Dezember 2022, 21:05:17
Ich habe noch zwei Verständnisfragen.

Die leere Datei wird weswegen erzeugt/benötigt?
Die obere renew Funktion mit dem download und den zwei Parse Funktionen wird wann genau aktiv?
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 23 Dezember 2022, 21:31:16
1. fürs mergen. Quasi als Basis, damit nicht die "teure" gedownloadete Datei verwendet wird. Technisch wird es nicht notwendig sein, aber ich (!) kann es nicht besser. Besser wäre es, wenn die Datei vorhandene gefilterte Datei erst gelöscht wird, wenn die Downloads abgeschlossen sind.
2. wenn sich die Senderliste geändert hat. Da es keine einzelne Merge-Funktion gibt, habe ich die downloadmerge genutzt. Der Timer ist notwendig, weil beim Start von Fhem das Reading sender kurzzeitig leer ist.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 23 Dezember 2022, 22:15:50
Zitat von: Damian am 23 Dezember 2022, 10:26:24
$TR wird wie folgt abgebildet:

  $wcmd =~ s/\$TR\{/\$hash->{$table}{tr}\{/g;

Offenbar kann in Perl die Referenz keine Berechnung sein, reine Variablen sollten funktionieren.

Ich muss meine Aussage korrigieren. Perl kann sehr wohl Berechnungen als Namen im Hash vornehmen, das Problem wird wohl sein, dass die Variable, die du angibst zum späteren Zeitpunkt nicht bekannt ist, wo die Auswertung stattfindet. Mit Instanzvariablen $_... müsste es dagegen klappen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Dezember 2022, 22:31:32
Zitat von: Damian am 23 Dezember 2022, 22:15:50
Ich muss meine Aussage korrigieren. Perl kann sehr wohl Berechnungen als Namen im Hash vornehmen, das Problem wird wohl sein, dass die Variable, die du angibst zum späteren Zeitpunkt nicht bekannt ist, wo die Auswertung stattfindet. Mit Instanzvariablen $_... müsste es dagegen klappen.

Mein erster kurzer Test sagt leider nein. Vielleicht habe ich aber auch noch was anderes falsch gemacht oder es ist irgendein Folgeproblem...
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 23 Dezember 2022, 22:44:27
Zitat von: mumpitzstuff am 23 Dezember 2022, 22:31:32
Mein erster kurzer Test sagt leider nein. Vielleicht habe ich aber auch noch was anderes falsch gemacht oder es ist irgendein Folgeproblem...

Also bei mir funktionieren sogar lokale Variablen:

defmod di_tr DOIF ##
attr di_tr uiTable {package ui_Table;;\
my $a=1;;\
$TR{$a+1} = "style='font-weight:bold'";;\
}\
"test"\
"test2"\
"test3"

Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Dezember 2022, 22:46:52
Ich habe jetzt noch dein erweitertes userattr übernommen und in den wget Zeilen lösche ich die Datei bei einem Fehler, dadurch sollte das nachfolgende entpacken schief gehen und die bestehende Datei nicht überschrieben werden.
Ich werde jetzt deine Version im ersten Beitrag verlinken und den Link anpassen, falls du eine Änderung posten solltest.

Ein wirkliches Killerfeature (falls du noch eine Challenge suchst) wäre übrigens folgendes: Anstatt next immer alle x Minuten zu parsen, könnte man sich beim parsen auch die am nächsten liegende Anfangszeit der Folgesendungen aller Sender merken und den entsprechenden Timer auf diesen Wert setzen. Dadurch würde man sich einige parse Vorgänge sparen.

Beispiel: aktuelle Zeit ist 22:00 Uhr und wir haben 3 Sender A, B und C. Die nächste Sendung von A beginnt um 23:30 Uhr, die von B um 22:15 Uhr und die von C um 0:00 Uhr. Also merken wir uns 22:15 Uhr und parsen erst wieder, wenn diese Zeit erreicht ist.

Btw. dein reparse jede Minute ist krasser Overkill. Es gibt so gut wie keine Sendung, die nicht zu einer Zeit startet, die nicht ein Vielfaches von 5 ist. Daher kannst du dein reparse auch auf 5 Minuten setzen, ohne etwas zu verpassen. Außerdem solltest du dir Gedanken darüber machen, wie du verhinderst, dass ein reparse getriggert wird, wenn der Download noch läuft. In meiner Version laufen beide Dinge nicht zur selben Zeit ab und Kollisionen sind ausgeschlossen. Ich würde dir empehlen, den Download auf 00:01 zu setzen und dein reparse alle 5 Minuten anzusetzen. Dann hast du genau 4 Minuten für den Download, in denen DOwnload und Parse nicht kollidieren können.

defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  ## sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:DasErste\.|ZDF\.|ZDFinfo\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeo(?:HD|Wild)\.|GeoTV\.|CuriosityChannel\.|Sky1\.|WELT\.|phoenix\.|ServusHD\.|BILD\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.|CrimeInvestigation\.|ComedyCentralVIVA\.|Universal\.|DiscoveryHD\.|eSports1\.)/;;\
  ## telnet port must not be password protected (open)\
  ## this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  ## can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem';;\
  $_dataFile = $_path.'/rytecDE_Basic';;\
  $_server = AttrVal("$SELF", "server", "http://www.xmltvepg.nl");;\
  ## enable/disable unused channel filtering on filemerge (enabled = small file and less readings = faster)\
  $_filterChannels = 1;;\
  ## enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  ## enable/disable use of Time::Piece (timepiece is faster but not installed on some systems)\
  $_timepiece = 0;;\
\
  ## internal variables\
  $_startTimes = ();;\
\
\
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    ##$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
\
      ## fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      ## slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
\
    foreach my $d (sort keys %::defs) \
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
\
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
\
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
\
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
\
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
\
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
        ## filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
\
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
\
          if ($i < 3 && 'next' eq $mode)\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $readingName;;\
            my $readingValue;;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
            $readingValue = substr(FmtDateTime($start), 0, 10);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
            $readingValue = substr(FmtDateTime($start), 11, 8);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
            if (exists($_->{'sub-title'}{'value'}))\
            {\
              $readingValue = filterText($_->{'sub-title'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
            if (exists($_->{'desc'}{'value'}))\
            {\
              $readingValue = filterText($_->{'desc'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $k++;;\
            $i++;;\
          }\
\
          if ($n < 3 && 'prime' eq $mode)\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
\
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $n++;;\
            }\
          }\
\
          if ($k >= 10)\
          {\
            ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
\
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
\
    return %{$_startTimes};;\
  }\
\
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';;\
\
    ## other server see below\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
\
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl\
    ## http://91.121.106.172/~rytecepg/epg_data\
    ## http://rytecepg.epgspot.com/epg_data\
    ## http://epg.vuplus-community.net\
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
\
    ## download and merge other files here if needed\
\
    return $output;;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
\
    ## prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
\
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
\
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
\
    $output = tvDownloadMerge();;\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
\
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
\
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
\
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
\
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
\
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
\
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_PARSE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
\
  if ([+00:15])\
  {\
    startParse("$SELF", 'next');;\
  }\
\
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST userattr server:http://www.xmltvepg.nl,http://epg.vuplus-community.net,http://91.121.106.172/~rytecepg/epg_data,http://rytecepg.epgspot.com/epg_data
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST event-on-change-reading .*
attr doif_TEST room TV
attr doif_TEST server http://www.xmltvepg.nl
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
    \
  ## 42 normal channels, 2 heading lines and 42 prime channels\
  ## 44 = 42 (normal channels) + 2 (headings)\
  ## 86 = 42 (normal channels) + 2 (headings) + 42 (prime channels)\
  ## 43 = 42 (normal channels) + 1 (first heading)\
  $TR{0,44} = "style='color:yellow;;;;text-align:center;;;;font-weight:bold;;;;font-size:18px'";;\
  $TD{0..42,44..86}{2,4} = "style='font-size:16px;;;;border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..42,44..86}{0} = "align='center' style='border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..86}{1,3,5,6} = "style='font-size:16px;;;;'";;\
  $TD{43}{0..6} = "style='border-top-style:solid;;;;border-bottom-style:solid;;;;border-color:#CCCCCC;;;;border-top-width:1px;;;;border-bottom-width:1px;;;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub showIconIP\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
    \
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVSET($SELF,next,DasErste,ard,<ir blaster device>,<ir blaster command>)\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVIP($SELF,next,DasErste,ard,VIEW1,29438503040)\
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,DasErste,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,ProSieben,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,KabelEins,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,Universal,universal)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,next,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,phoenix,phoenix)\
TPL_TV($SELF,next,ZDFinfo,zdfinfo)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,WELT,welt)\
TPL_TV($SELF,next,ServusHD,servus)\
TPL_TV($SELF,next,BILD,bild)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,GeoTV,geotv)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,NatGeoWild,natgeowild)\
TPL_TV($SELF,next,DiscoveryHD,discovery)\
TPL_TV($SELF,next,Sky1,skyone)\
TPL_TV($SELF,next,CuriosityChannel,curiosity)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
TPL_TV($SELF,next,eSports1,esports1)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,ProSieben,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,KabelEins,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,Universal,universal)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,prime,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,phoenix,phoenix)\
TPL_TV($SELF,prime,ZDFinfo,zdfinfo)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,WELT,welt)\
TPL_TV($SELF,prime,ServusHD,servus)\
TPL_TV($SELF,prime,BILD,bild)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,GeoTV,geotv)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,NatGeoWild,natgeowild)\
TPL_TV($SELF,prime,DiscoveryHD,discovery)\
TPL_TV($SELF,prime,Sky1,skyone)\
TPL_TV($SELF,prime,CuriosityChannel,curiosity)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)\
TPL_TV($SELF,prime,eSports1,esports1)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 23 Dezember 2022, 22:51:18
Ich würde solche langen Code-Passagen als Zip-Datei anhängen, sonst kann man solche Threads schlecht lesen. Vermutlich ist mein vorheriger Post schon untergegangen ;)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Dezember 2022, 22:51:33
Zitat von: Damian am 23 Dezember 2022, 22:44:27
Also bei mir funktionieren sogar lokale Variablen:

defmod di_tr DOIF ##
attr di_tr uiTable {package ui_Table;;\
my $a=1;;\
$TR{$a+1} = "style='font-weight:bold'";;\
}\
"test"\
"test2"\
"test3"


Komisch. Dann müssen das irgendwelche Zusammenhänge mit dem recht umfangreichen DOIF sein, die hier zum tragen kommen. In dem Beitrag über diesen habe ich das aktuell DOIF mal gepostet und hier probiert die 44 aus dieser Zeile durch eine Variable zu ersetzen. Es ist mir nicht gelungen. Ich verwende auch die Variable erst nach einem Komma, vielleicht spielt das auch eine Rolle...

$TR{0,44} = "style='color:yellow;;;;text-align:center;;;;font-weight:bold;;;;font-size:18px'";;\

Das färbt die Überschriften der aktuellen Sendungen und der Prime Sendungen gelb ein, ist also eigentlich recht gut sichtbar.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 23 Dezember 2022, 23:02:31
defmod di_tr DOIF ###
attr di_tr uiTable {\
    package ui_Table;;\
    my $a=1;;\
    $TR{0,$a+1} = "style='font-weight:bold'";;\
}\
"test"\
"test2"\
"test3"


Das geht schon nicht mehr.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 23 Dezember 2022, 23:12:32
Es liegt an dem Parsen nach dem Komma:

  $wcmd =~ s/\$hash->\{$table\}\{tr\}\{([\d,.]*)?\}.*(\".*\")/for my \$i ($1) \{\$hash->\{$table\}\{tr\}\{\$i\} = $2\}/g;

Du könntest auf zwei Definitionen ohne Komma ausweichen:

my $s= "style='color:yellow;text-align:center;font-weight:bold;font-size:18px'";
$TR{0}=$s;
$TR{44}=$s;
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 24 Dezember 2022, 00:14:35
@Damian:
  $TR{0} = "style=
  $TR{($_rowsnext + 2)} = "style=
  $TR{1..($_rowsnext),($_rowsnext + 3)..$lastrow} = "style=
  $TR{($_rowsnext + 1)} = "style=
  $TD{0..$lastrow}{0} = "align=
  $TD{0..$_rowsnext, ($_rowsnext + 3)..$lastrow}{1,3,5} = "style=

Diese Varianten funktionieren alle, bei einigen auch mit Variablen nach dem Komma. Aber
  $TR{0,$_rowsnext + 2)} = "style=
geht nicht.

@mumpitzstuff:
Das mit den Parsen nach Uhrzeit schau ich mir mal an, klingt nicht so dumm. Muss nur schauen, wo ich es reinpacke. Das mit der 1 min habe ich nur gemacht, damit ich in der Testphase sooo lange auf Ergebnisse/Fehlermeldungen warten muss.
Tante Edit hat es fast erledigt, prime Parsing funkt noch dazwischen, aber jetzt erstmal Augen zu!
Tante Edit hat es doch noch gelöst...
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 24 Dezember 2022, 10:35:59
Ich würde hier tatsächlich auf Perl zurückgreifen, das funktioniert dann immer:

defmod di_tr DOIF ##
attr di_tr uiTable {package ui_Table;;\
my $a=0;;\
for my $i (($a+0),($a+2)) {$TR{$i}="style='font-weight:bold'"};;\
}\
"test"\
"test2"\
"test3"
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 26 Dezember 2022, 03:50:00
Das Parsen nach Startzeit war nicht sooo toll, es funktioniert nur richtig, wenn $_updateBasedOnStarttimes = 1 gesetzt ist. Deshalb nutze ich jetzt die Stoppzeit, bis jetzt keine Probleme!
Die Einsparung ggü der 5 min Variante ist in der Praxis minimal, dafür werden aus Sendungen außerhalb des Rasters (Wetter) zu ihrer Zeit aktualisiert.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 28 Dezember 2022, 11:06:49
Ich habe mir das jetzt auch noch einmal angesehen und es ist tatsächlich erschreckend, wie oft ein Update notwendig ist. In den letzten 12h hatte ich nur ein einziges 5 Minuten Raster, wo kein Update notwendig war. Die Funktion bringt deshalb doch nicht so viel, wie ursprünglich gedacht, zumindest dann nicht, wenn man eine gewisse Anzahl von Sendern überschreitet.
Aber die Sache hatte auch ein Gutes, ich habe dabei noch einen Bug entdeckt und beheben können, der mit den startTimes zusammen hängt und dafür gesorgt hat, das zu viele Readings geupdated wurden. Ich bereinige das noch und poste es dann in den nächsten Tagen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 28 Dezember 2022, 12:26:51
Hoffentlich muss ich dann nicht von vorn anfangen :D

Könntest du eventuell gleich gucken, ob beim Neustart/init $_updateBasedOnStarttimes = 1 (virtuell ;) ) gesetzt werden kann.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 28 Dezember 2022, 12:42:18
Ich habe das sowieso immer angeschaltet, also auf 1. Eigentlich könnte man auch auf den Schalter verzichten und das Verhalten zum Standard erklären.
Aber zurück zu deiner Frage, die verstehe ich nicht ganz. Selbst wenn du das ausgeschaltet haben solltest und das jetzt beim init. kurz einschalten möchtest, bringt es doch gerade da eigentlich gar nichts. Nach einem Neustart stehen noch gar keine startTimes zur Verfügung. Diese werden beim ersten Durchlauf generiert.

Der Bug befindet sich in dieser Zeile:

for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\

muss sein:

for (my $i = 0;; $i < scalar(@startTimes);; $i += 2)\

Das hat dazu geführt, das nur die Hälfte der startTimes geupdated wurden.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 28 Dezember 2022, 19:58:03
Na vllt ist das auch der Fehler, den ich mit meinem Vorschlag behoben haben wollte. Nur habe ich die falsche Ursache vermutet.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 28 Dezember 2022, 21:56:47
defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  ## sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  ##use Encode qw(encode_utf8 decode_utf8);;\
\
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:DasErste\.|ZDF\.|ZDFinfo\.|Sat1\.|RTL2?\.|Pro(Sieben|SiebenMaxx)\.|DMax\.|Vox\.|KabelEins(?:Classic|Doku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeo(?:HD|Wild)\.|GeoTV\.|CuriosityChannel\.|Sky1\.|WELT\.|phoenix\.|ServusHD\.|BILD\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.|CrimeInvestigation\.|ComedyCentralVIVA\.|Universal\.|DiscoveryHD\.|eSports1\.)/;;\
  ## telnet port must not be password protected (open)\
  ## this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  ## can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem';;\
  $_dataFile = $_path.'/rytecDE_Basic';;\
  $_server = AttrVal("$SELF", "server", "http://www.xmltvepg.nl");;\
  ## enable/disable unused channel filtering on filemerge (enabled = small file and less readings = faster)\
  $_filterChannels = 1;;\
  ## enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  ## enable/disable use of Time::Piece (timepiece is faster but not installed on some systems (sudo cpanm Time::Piece))\
  $_timepiece = 0;;\
\
  ## internal variables\
  $_startTimes = ();;\
\
\
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    ##$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
\
      ## fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      ## slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
\
    foreach my $d (sort keys %::defs) \
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
\
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
\
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
\
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
\
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    my $old = time() + $_timeAdjust;;\
\
    ## check if any update is needed\
    if ((0 != $_updateBasedOnStarttimes) && ('prime' ne $mode) && keys(%{$_startTimes}))\
    {\
      my $nothingTodo = 1;;\
      foreach (keys(%{$_startTimes}))\
      {\
        if ($_startTimes{$_} <= $old)\
        {\
          $nothingTodo = 0;;\
          ::Log3 $device, 4, $device.': Update is not blocked because at least one actual program is finished (reading: '.$_.', start: '.$_startTimes{$_}.', old: '.$old.').';;\
          last;;\
        }\
      }\
      \
      if (0 != $nothingTodo)\
      {\
        ::Log3 $device, 4, $device.': Update is blocked because no actual program was finished.';;\
        return %{$_startTimes};;\
      }\
    }\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
        ## filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $n = 0;;\
\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $i = 0;;\
\
              if (0 != $_updateBasedOnStarttimes)\
              {\
                $_startTimes{$reading} = $stop;;\
              }\
            }\
            else\
            {\
              ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (reading: '.$reading.', start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
\
          if ($i < 3 && 'next' eq $mode)\
          {\
            my $fi = sprintf("%03d", $i);;\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $readingName;;\
            my $readingValue;;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
            $readingValue = substr(FmtDateTime($start), 0, 10);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
            $readingValue = substr(FmtDateTime($start), 11, 8);;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
            if (exists($_->{'sub-title'}{'value'}))\
            {\
              $readingValue = filterText($_->{'sub-title'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
            if (exists($_->{'desc'}{'value'}))\
            {\
              $readingValue = filterText($_->{'desc'}{'value'});;\
            }\
            else\
            {\
              $readingValue = 'na';;\
            }\
            $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
            $k++;;\
            $i++;;\
          }\
\
          if ($n < 3 && 'prime' eq $mode)\
          {\
            my $start = xmltv2epoch($_->{'start'}{'value'});;\
            my $fmtStart = FmtDateTime($start);;\
            my $bdate = substr($fmtStart, 0, 10);;\
            my $btime = substr($fmtStart, 11, 8);;\
\
            if ($bdate.' '.$btime gt $primeTime)\
            {\
              my $fn = sprintf("%03d", $n);;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $n++;;\
            }\
          }\
\
          if ($k >= 10)\
          {\
            ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        ##::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
\
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
\
    return %{$_startTimes};;\
  }\
\
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';;\
\
    ## other server see below\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
\
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl\
    ## http://91.121.106.172/~rytecepg/epg_data\
    ## http://rytecepg.epgspot.com/epg_data\
    ## http://epg.vuplus-community.net\
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
\
    tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
\
    ## download and merge other files here if needed\
\
    return $output;;\
  }\
\
  sub startDownload($)\
  {\
    my $name = shift;;\
\
    ## prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
\
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
\
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
\
    $output = tvDownloadMerge();;\
\
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
\
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_DOWNLOAD});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
\
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
\
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
\
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, @newStartTimes) = split("\\|", shift);;\
\
    for (my $i = 0;; $i < scalar(@newStartTimes);; $i += 2)\
    {\
      $_startTimes{$newStartTimes[$i]} = $newStartTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
\
    delete($_blockingcalls{PID_PARSE});;\
\
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 180, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 420, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:00:30|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
\
  if ([+:05])\
  {\
    ## start in a raster of 5min\
    startParse("$SELF", 'next');;\
  }\
\
  if ([00:32:30])\
  {\
    ## start between next updates\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST userattr server:http://www.xmltvepg.nl,http://epg.vuplus-community.net,http://91.121.106.172/~rytecepg/epg_data,http://rytecepg.epgspot.com/epg_data
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST event-on-change-reading .*
attr doif_TEST room TV
attr doif_TEST server http://www.xmltvepg.nl
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
    \
  ## 39 normal channels, 2 heading lines and 38 prime channels\
  ## 41 = 39 (normal channels) + 2 (headings)\
  ## 79 = 39 (normal channels) + 2 (headings) + 38 (prime channels)\
  ## 40 = 39 (normal channels) + 1 (first heading)\
  $TR{0,41} = "style='color:yellow;;;;text-align:center;;;;font-weight:bold;;;;font-size:18px'";;\
  $TD{0..39,41..79}{2,4} = "style='font-size:16px;;;;border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..39,41..79}{0} = "align='center' style='border-right-style:solid;;;;border-color:#CCCCCC;;;;border-right-width:1px;;;;'";;\
  $TD{0..79}{1,3,5,6} = "style='font-size:16px;;;;'";;\
  $TD{40}{0..6} = "style='border-top-style:solid;;;;border-bottom-style:solid;;;;border-color:#CCCCCC;;;;border-top-width:1px;;;;border-bottom-width:1px;;;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub showIconIP\
  {\
    my ($icon, $device, $state) = @_;;\
\
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"". ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
    \
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;; \
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';".$desc."';)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVSET($SELF,next,DasErste,ard,<ir blaster device>,<ir blaster command>)\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
## example: TPL_TVIP($SELF,next,DasErste,ard,VIEW1,29438503040)\
DEF TPL_TVIP(showIconIP("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,DasErste,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,ProSieben,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,KabelEins,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,Universal,universal)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,next,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,phoenix,phoenix)\
TPL_TV($SELF,next,ZDFinfo,zdfinfo)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,WELT,welt)\
TPL_TV($SELF,next,ServusHD,servus)\
TPL_TV($SELF,next,BILD,bild)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,GeoTV,geotv)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,NatGeoWild,natgeowild)\
TPL_TV($SELF,next,DiscoveryHD,discovery)\
TPL_TV($SELF,next,Sky1,skyone)\
TPL_TV($SELF,next,CuriosityChannel,curiosity)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,eSports1,esports1)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,DasErste,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,ProSieben,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,KabelEins,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,Universal,universal)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ComedyCentralVIVA,comedycentral)\
TPL_TV($SELF,prime,CrimeInvestigation,crimeinvest)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,phoenix,phoenix)\
TPL_TV($SELF,prime,ZDFinfo,zdfinfo)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,WELT,welt)\
TPL_TV($SELF,prime,ServusHD,servus)\
TPL_TV($SELF,prime,BILD,bild)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,GeoTV,geotv)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,NatGeoWild,natgeowild)\
TPL_TV($SELF,prime,DiscoveryHD,discovery)\
TPL_TV($SELF,prime,Sky1,skyone)\
TPL_TV($SELF,prime,CuriosityChannel,curiosity)\
TPL_TV($SELF,prime,TLC,tlc)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 29 Dezember 2022, 11:27:04
Ich habe inzwischen 90%, naja, sagen wir 80% von deinem Code verstanden. Hier noch mal meine aktuelle Variante zur Diskussion (inkl. deiner Änderungen vom letzten Post).
Neu:
- "rytecDE_leer" wird nicht mehr benötigt
- Änderungen an den TPL erzeugen nicht mehr automatisch einen neuen Durchlauf, sondern werden über "set TV_Programm _refill" manuell angestoßen. Die automatische Variante ergab mir zuviele "warnings"
- Datum und Zeit wurde zu einem Reading zusammengefasst (-20% Readings ;))
- Ein TPL wurde für Mediathek-Links erstellt.
- Download, Merge und Parse sind separate Prozesse
- Merge wird nicht mehr mehrfach aufgerufen (((Start+Ziel)+Ziel)+Ziel), sondern in einer foreach-Schleife
- Das Ende von Merge ruft automatisch Parse auf, daher keine feste Verzögerung mehr nötig
- "rytecDE_SportMovies" muss nur noch an einer Stelle aktiviert (#) werden

defmod TV_Programm DOIF subs\
{\
  \
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  $_name = "$SELF";;\
  $_path = qx(pwd 2>&1);;\
  $_path =~ s/\/?\s/\//;;\
  #'/opt/fhem/';;\
  $_data = '/rytecDE_filt_'.$_name;;\
  $_dataFile = $_path.$_data;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  $_server = AttrVal($_name,"server","http://epg.vuplus-community.net");; \
  my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
  $channelFilter =~ s/\|$//;;\
  $_channelFilter = qr/^(?:$channelFilter)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
\
  sub filterText($)\
  {\
    my $text = shift;;\
    \
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
    \
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
    \
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
      \
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs)\
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
      \
      $telnet = $d;;\
      last;;\
    }\
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
      \
      if (defined($ret))\
      {\
        Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
      \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub sendTelnet($$)\
  {\
    my ($name, $sendTelnet) = @_;;\
    my $port;;\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    my $output = '';;\
    $output .= qx(wget $_server/$data.xz -O $_path/$data.xz 2>&1);;\
    $output .= qx(xz -df $_path/$data.xz 2>&1);;\
    \
    return $name.'|'. $data.'|'.$output;;\
  }\
\
  sub DOIF::endDownload($)\
  {\
    my ($name, $data, $output) = split("\\|", shift);;\
    \
    Log3 $name, 5, $name.': '.$output;;\
    Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    my $blockname = "PID_DOWNLOAD".$data;;\
    delete($_blockingcalls{$blockname});;\
    $_lastdown = time();;\
    sendTelnet($name,";;setreading $name $data $_lastdown;;");;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    \
    my $blockname = "PID_DOWNLOAD".$data;;\
    delete($_blockingcalls{$blockname});;\
    Log3 $name, 1, $name.': Blocking call aborted (download).';;\
    $_lastdown = 0;;\
    sendTelnet($name,";;setreading $name $data $_lastdown;;");;\
  }\
\
  sub startDownload($)\
  {\
    my $fileName = shift;;\
    my $dataFile = $_path.$fileName;;\
    \
    # prevent download spamming\
    if (-e $dataFile)\
    {\
      my $btime = ((time() - (stat($dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      \
      if ($btime < 1.0)\
      {\
        Log3 $_name, 1, $_name.': Download of '.$fileName.' skipped because file is not older than 1 day ('.($btime).').';;\
        return;;\
      }\
    }\
    \
    my $blockname = "PID_DOWNLOAD".$fileName;;\
    if (defined($_blockingcalls{$blockname}))\
    {\
      Log3 $_name, 3, $_name.': Blocking call already running (download).';;\
      ::BlockingKill($_blockingcalls{$blockname});;\
    }\
    \
    $_blockingcalls{$blockname} = ::BlockingCall('DOIF::doDownload', $_name.'|'.$fileName, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $_name.'|'.$fileName);;\
  }\
\
  sub DOIF::doMerge($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    my $output = '';;\
    \
    my @srcName = ('rytecDE_Basic','rytecDE_Common','rytecDE_SportMovies');;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels = '';;\
    my $programms = '';;\
    my $end = '';;\
    my $pos;;\
    my $output = "";;\
    my $ftime = 2;;\
    \
    open($fh, '<', $_path.$srcName[0]) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
    \
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
    \
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
    \
    if (0 != $_filterChannels)\
    {\
      my $FilesCount = (@srcName);;\
      for ($i=0;;$i<$FilesCount;;$i++)\
      {\
$src = $srcName[$i];;\
if (-e $src)\
{\
          open($fh, '<', $src) or die "Can't open file $!";;\
          read($fh, $src, -s $fh);;\
          close($fh);;\
          while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
          {\
            $_ = $1;;\
            \
            if ($2 =~ $_channelFilter)\
            {\
              $channels .= $_;;\
            }\
          }\
          \
          while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
          {\
            $_ = $1;;\
            \
            if ($2 =~ $_channelFilter)\
            {\
              $programms .= $_;;\
            }\
          }\
        }\
      }\
    }\
    open($fh, '>', $_dataFile) or die "Can't open file $!";;\
    print $fh $start.$channels.$programms.$end;;\
    close($fh);;\
    \
    return $name.'|'.$output;;\
  }\
\
  sub DOIF::endMerge($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    Log3 $name, 5, $name.': '.$output;;\
    Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_MERGE});;\
    $_lastmerge = time();;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
  }\
\
  sub DOIF::abortMerge($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_MERGE});;\
    \
    Log3 $name, 1, $name.': Blocking call aborted (download).';;\
    $_lastmerge = 0;;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
  }\
\
  sub startMerge($)\
  {\
    my $name = shift;;\
    \
    my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
    $channelFilter =~ s/\|$//;;\
    $_channelFilter = qr/^(?:$channelFilter)/;;\
    \
    if (defined($_blockingcalls{PID_DOWNLOADrytecDE_Basic})\
    or defined($_blockingcalls{PID_DOWNLOADrytecDE_Common})\
    or defined($_blockingcalls{PID_DOWNLOADrytecDE_SportMovies}))\
    {\
      set_Exec('init_merge', 10, 'startMerge("$SELF")');;\     
      return;;\
    }\
    if (defined($_blockingcalls{PID_MERGE}))\
    {\
      Log3 $name, 3, $name.': Blocking call already running (merge).';;\
      \
      ::BlockingKill($_blockingcalls{PID_MERGE});;\
    }\
    \
    $_lastmerge = 0;;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
    \
    $_blockingcalls{PID_MERGE} = ::BlockingCall('DOIF::doMerge', $name.'|'.$_data, 'DOIF::endMerge', 300, 'DOIF::abortMerge', $name);;\
  }\
\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $n = 999;;\
    my $p = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    my $nextparse = time() + 3600;;\
    my $start;;\
    my $stop;;\
    my $startform;;\
    my $readingValue;;\
    my $setreading;;\
    my $old = time() + $_timeAdjust;;\
    \
    ## check if any update is needed\
    if ((0 != $_updateBasedOnStarttimes) && ('prime' ne $mode) && keys(%{$_startTimes}))\
    {\
      my $nothingTodo = 1;;\
      foreach (keys(%{$_startTimes}))\
      {\
        if ($_startTimes{$_} <= $old)\
        {\
          $nothingTodo = 0;;\
          ::Log3 $device, 4, $device.': Update is not blocked because at least one actual program is finished (reading: '.$_.', start: '.$_startTimes{$_}.', old: '.$old.').';;\
          last;;\
        }\
      }\
      \
      if (0 != $nothingTodo)\
      {\
        ::Log3 $device, 4, $device.': Update is blocked because no actual program was finished.';;\
        return %{$_startTimes};;\
      }\
    }\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
    \
    if (!$@)\
    {\
#      my $old = time() + $_timeAdjust;;\
      \
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        $stop = xmltv2epoch($_->{'stop'}{'value'});;\
        \
           # filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $_->{'channel'}{'value'};;\
            $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $p = 0;;\
    \
            $nextparse = $stop if (($nextparse > $stop) and ($stop > (time() + 30)));;\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $n = 0;;\
      $_startTimes{$reading} = $stop if (0 != $_updateBasedOnStarttimes);;\
            }\
            else\
            {\
            Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (reading: '.$reading.', start: '.$_startTimes{$reading}.', old: '.$old.').';;\
#              Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
  \
          $start = xmltv2epoch($_->{'start'}{'value'});;\
      $startform = substr(FmtDateTime($start), 0, 19);;\
  \
          if (($p < 3 && 'prime' eq $mode && $startform gt $primeTime) or ($n < 3 && 'next' eq $mode))\
          {\
            $readingValue = "";;\
            \
            $setreading .= ";;setreading $device _$reading";;\
    if ('prime' eq $mode)\
    {\
              $setreading .= "_prime_".sprintf("%03d", $p++);;\
    }\
    else\
    {\
              $setreading .= "_next_".sprintf("%03d", $n++);;\
    }\
    \
            $readingValue = $startform;;\
            $sendTelnet .= $setreading."_1start $readingValue";;\
    \
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= $setreading."_2title $readingValue";;\
    \
            $readingValue = ((exists($_->{'sub-title'}{'value'})) ? filterText($_->{'sub-title'}{'value'}) : 'na');;\
            $sendTelnet .= $setreading."_3stitle $readingValue";;\
    \
            $readingValue = ((exists($_->{'desc'}{'value'})) ? filterText($_->{'desc'}{'value'}) : 'na');;\
            $sendTelnet .= $setreading."_4desc $readingValue";;\
    \
            $k++;;\
          }\
  \
          if ($k >= 8)\
          {\
    #Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
            $k = 0;;\
            $sendTelnet = '';;\
          }\
        }\
      }\
      \
      if ('' ne $sendTelnet or 'next' eq $mode)\
      {\
$sendTelnet .= ";;setreading $device nextparse ". ($nextparse - time() + 10) if ('next' eq $mode);;\
         #Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$mode.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, $mode, @newStartTimes) = split("\\|", shift);;\
    \
    for (my $i = 0;; $i < scalar(@newStartTimes);; $i += 2)\
    {\
      $_startTimes{$newStartTimes[$i]} = $newStartTimes[$i + 1];;\
    }\
    \
    Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    my $testparse = "PID_PARSE".$mode;;\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my ($name, $mode) = split("\\|", shift);;\
    \
    Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
    \
    my $testparse = "PID_PARSE".$mode;;\
    delete($_blockingcalls{PID_PARSE});;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    \
    if (defined($_blockingcalls{PID_MERGE}))\
    {\
      return;;\
    }\
    my $testparse = "PID_PARSE".$mode;;\
    if (defined($_blockingcalls{$testparse}))\
    {\
      Log3 $name, 3, $name.': Blocking call already running (parse).';;\
      ::BlockingKill($_blockingcalls{$testparse});;\
    }\
    \
    my $port;;\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{$testparse} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name.'|'.$mode);;\
  }\
}\
\
init\
{\
  fhem("set $SELF down");;\
  set_Exec('init_merge', 20, 'startMerge("$SELF")');;\
  set_Exec('init_next_sik', 7200, 'startParse("$SELF", "next")');;\
}\
down\
{\
  [00:05|Mo Do];;\
  set_Exec('init_down_Basic', 1, 'startDownload("rytecDE_Basic")');;\
  set_Exec('init_down_Common', 2, 'startDownload("rytecDE_Common")');;\
#  set_Exec('init_down_Sport', 3, 'startDownload("rytecDE_SportMovies")');;\
}\
merge\
{\
  [01:05|Mo Do];;\
  set_Exec('init_merge', 10, 'startMerge("$SELF")');;\
}\
parse_next_manu\
{\
  [$SELF:lastmerge];;\
  set_Exec('init_next', 5, 'startParse("$SELF", "next")');;\
}\
parse_next\
{\
  set_Exec('init_next', [$SELF:nextparse], 'startParse("$SELF", "next")');;\
  set_Exec('init_next_sik', 3601, 'startParse("$SELF", "next")');;\
}\
parse_prime\
{\
  [00:30];;\
  [$SELF:lastmerge];;\
  set_Exec('init_prime', 10, 'startParse("$SELF", "prime")');;\
}\
_refill\
{\
#  if ([$SELF:sender])\
  {\
    if (ReadingsVal("$SELF","sender","ZDF\\.") ne $_Senderliste)\
    {\
      fhem("deletereading $SELF .*(next|prime)_.*  200000");;\
      fhem("setreading $SELF sender $_Senderliste");;\
      fhem("set $SELF down");;\
      set_Exec('init_merge', 20, 'startMerge("$SELF")');;\
    }\
    fhem("setreading $SELF rowsnext $_rowsnext");;\
    fhem("setreading $SELF rowsprime $_rowsprime");;\
    \
  }\
}
attr TV_Programm userattr server:http://epg.vuplus-community.net,http://www.xmltvepg.nl,http://91.121.106.172/~rytecepg/epg_data,http://www.vuplus-community.net/rytec
attr TV_Programm alias Aktuelles TV-Programm
attr TV_Programm event-on-change-reading .*
attr TV_Programm room Wohnzimmer
attr TV_Programm server http://www.xmltvepg.nl
attr TV_Programm uiTable {\
  package ui_Table;;\
  \
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  my $rowsnext = ::ReadingsVal("$SELF","rowsnext",0);;\
  my $rowsprime = ::ReadingsVal("$SELF","rowsprime",0);;\
  my $lastrow = $rowsnext + $rowsprime + 2;;\
  \
  $TR{0} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px;;'";;\
  $TR{($rowsnext + 2)} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px;;'";;\
  $TR{1..($rowsnext),($rowsnext + 4)..$lastrow} = "style='font-size:16px'";;\
  $TR{($rowsnext + 1)} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
#  $TD{0..$lastrow}{0} = "align='center'";;\
  $TD{0..$rowsnext, ($rowsnext + 3)..$lastrow}{1,3,5} = "style='border-left-style:solid;;border-color:#CCCCCC;;border-left-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($mode, $icon, $show, $device, $state) = @_;;\
    $_rowsprime_temp += ($mode eq "prime" ? 1 : 0);;\
    $_rowsnext_temp += ($mode eq "next" ? 1 : 0);;\
    $_Senderliste_temp =~ s/$icon\\.\|//;;\
    $_Senderliste_temp .= $icon . "\\.|";;\
    \
    if ($device && $state)\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("$show")."</a>";;\
#      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      if ($device)\
      {\
        return "<a href=\"$device\" target=\"IPTV\">".ICON("tv/20px-Icon-video-library")." ".ICON("$show")."</a>";;\
      }\
      else\
      {\
        return ICON("$show");;\
      }\
    }\
  }\
\
  sub unfold\
  {\
    my ($ReadingPre) = @_;;\
    my $title = ::ReadingsVal("$SELF","_${ReadingPre}_2title","-");;\
    my $desc = ::ReadingsVal("$SELF","_${ReadingPre}_3stitle","na")."\n\n". ::ReadingsVal("$SELF","_${ReadingPre}_4desc","na") ;;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
    \
    return substr(::ReadingsVal("$SELF","_${ReadingPre}_1start",""),11,5) . \
            "</td><td><a href=\"#!\" onclick=\"FW_okDialog(';$title<br>$desc';)\">$title</a>";;\
  }\
  \
  sub save_vars\
  {\
    $_Senderliste = $_Senderliste_temp ;;\
    $_rowsprime = $_rowsprime_temp;;\
    $_rowsnext = $_rowsnext_temp;;\
    return;;\
  }\
}\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$1", "$2", "$3", "$4", "$5")|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$1", "$2", "$3")|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), URL Mediathek\
DEF TPL_TVMT(showIcon("$1", "$2", "$3", "$4")|unfold("$2_$1_000")|unfold("$2_$1_001")|unfold("$2_$1_002"))\
\
DEF TPL_END(save_vars())\
\
$_Senderliste_temp = "";;$_rowsnext_temp = 0;;$_rowsprime_temp = 0;;"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Naechste Sendung"|"ab"|"Sendung"\
TPL_TVMT(next,DasErste,01 ARD,https://www.ardmediathek.de/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL2xpdmUvY2xpcC9hYmNhMDdhMy0zNDc2LTQ4NTEtYjE2Mi1mZGU4ZjY0NmQ0YzQ)\
TPL_TVMT(next,ZDF,02 ZDF,https://www.zdf.de/live-tv)\
TPL_TV(next,RTL,04 RTL)\
TPL_TV(next,RTL2,05 RTL2)\
TPL_TV(next,Vox,06 Vox)\
TPL_TV(next,VOXup,.. VOXup)\
TPL_TVMT(next,ProSieben,07 ProSieben,https://video.prosieben.de/livestreams/1)\
TPL_TVMT(next,Sat1,08 Sat1,https://video.prosieben.de/livestreams/2)\
TPL_TVMT(next,KabelEins,09 KabelEins,https://video.prosieben.de/livestreams/3)\
TPL_TVMT(next,3sat,10 3Sat,https://www.ardmediathek.de/live/Y3JpZDovLzNzYXQuZGUvTGl2ZXN0cmVhbS0zc2F0)\
TPL_TVMT(next,ARTE,11 Arte,https://www.ardmediathek.de/live/Y3JpZDovL2FydGUuZGUvTGl2ZXN0cmVhbS1BUlRF)\
TPL_TV(next,DMax,12 D-Max)\
TPL_TVMT(next,ServusHD,13 ServusTV,https://www.servustv.com/allgemein/p/jetzt-live/119753/)\
TPL_TVMT(next,NDRFernsehen,14 NDR,https://www.ardmediathek.de/live/Y3JpZDovL25kci5kZS9MaXZlc3RyZWFtLU5EUi1OaWVkZXJzYWNoc2Vu)\
TPL_TVMT(next,WDRFernsehen,15 WDR3,https://www.ardmediathek.de/live/Y3JpZDovL3dkci5kZS9CZWl0cmFnLTNkYTY2NGRlLTE4YzItNDY1MC1hNGZmLTRmNjQxNDcyMDcyYg)\
TPL_TVMT(next,HRFernsehen,16 HR3,https://www.ardmediathek.de/live/Y3JpZDovL2hyLmRlL0xpdmVzdHJlYW0tSFI)\
TPL_TVMT(next,SWRFernsehen,17 SWR,https://www.ardmediathek.de/live/Y3JpZDovL3N3ci5kZS8xMzQ4MTA0Mg)\
TPL_TVMT(next,MDRS-Anhalt,18 MDR,https://www.ardmediathek.de/live/Y3JpZDovL21kci5kZS9MaXZlc3RyZWFtLU1EUi1TYWNoc2Vu)\
TPL_TVMT(next,BRFernsehen,BR3,https://www.ardmediathek.de/live/Y3JpZDovL2JyLmRlL0xpdmVzdHJlYW0tQlItU8O8ZA)\
TPL_TVMT(next,rbbBerlin,RBB,https://www.ardmediathek.de/live/Y3JpZDovL3JiYi1vbmxpbmUuZGUvcmJiZmVybnNlaGVuL2xpdmVfYnJhbmRlbmJ1cmcvc2VuZGVwbGF0ei0tLWxpdmVzdHJlYW0tLS1icmFuZGVuYnVyZy0tLWhsczE)\
TPL_TV(next,ComedyCentralVIVA,19 ComedyCentral)\
TPL_TVMT(next,ProSiebenMaxx,20 pro7maxx,https://video.prosieben.de/livestreams/5)\
TPL_TV(next,SuperRTL,21 SuperRTL)\
TPL_TV(next,RTLNitro,22 Nitro)\
TPL_TVMT(next,Tele5,23 Tele5,https://tele5.de/live/)\
TPL_TVMT(next,Sat1Gold,24 Sat1 Gold,https://video.prosieben.de/livestreams/6)\
TPL_TVMT(next,phoenix,25 phoenix,https://www.ardmediathek.de/live/Y3JpZDovL3Bob2VuaXguZGUvTGl2ZXN0cmVhbS1waG9lbml4)\
TPL_TVMT(next,KabelEinsDoku,202 Kabel1doku,https://video.prosieben.de/livestreams/7)\
TPL_TV(next,N24Doku,203 n24 Doku)\
TPL_TVMT(next,ZDFinfo,204 ZDF Info,https://www.zdf.de/live-tv)\
TPL_TV(next,Sport1HD,300 DSF)\
TPL_TV(next,Eurosport1,301 Eurosport)\
TPL_TV(next,WELT,302 Welt n24)\
TPL_TVMT(next,ntv,303 n-tv,https://www.n-tv.de/mediathek/livestream/24-Stunden-ntv-Livestream-article9511936.html)\
TPL_TVMT(next,tagesschau24,304 tagesschau24,https://www.ardmediathek.de/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL3RhZ2Vzc2NoYXUvbGl2ZXN0cmVhbQ)\
TPL_TVMT(next,History,history,https://www.history.de/history-play/history-play-auf-amazon-prime.html)\
TPL_TV(next,TLC,TLC)\
TPL_TVMT(next,Sixx,?? Sixx,https://video.prosieben.de/livestreams/4)\
TPL_TV(next,HGTV,428 HGTV)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV(prime,DasErste,ard)\
TPL_TV(prime,ZDF,zdf)\
TPL_TV(prime,Sat1,sat1)\
TPL_TV(prime,RTL,rtl)\
TPL_TV(prime,RTL2,rtl2)\
TPL_TV(prime,ProSieben,pro7)\
TPL_TV(prime,DMax,dmax)\
TPL_TV(prime,Vox,vox)\
TPL_TV(prime,KabelEins,kabel1)\
TPL_TV(prime,KabelEinsDoku,kabel1doku)\
TPL_TV(prime,KabelEinsClassic,kabel1classic)\
TPL_TV(prime,ProSiebenMaxx,pro7maxx)\
TPL_TV(prime,Sixx,sixx)\
TPL_TV(prime,ntv,ntv)\
TPL_TV(prime,N24Doku,n24)\
TPL_TV(prime,History,history)\
TPL_TV(prime,TLC,tlc)\
TPL_END()

Wie immer mit meinen Sendern und html-Formatierungen. Code-Formatierungen habe ich versucht, dein System beizubehalten.
Die Merge-Variante ohne ChannelFilter habe ich rausgenommen (readingsVal gibt eh eine Vorgabe zurück, die könnte man noch auf ".*" anpassen), die ohne src-Datei ist durch die Schleife überflüssig geworden.

Tante Edit hat noch eine wichtige Änderung:
attr event-on-update-reading nextparse
Da sich diese Werte meistens so um die 5 min tummeln, kann es schon mal passieren, dass es kein change, sondern nur ein update gibt. Dann müsste der _sik ran, der ja erst in einer Stunde zuschlägt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 29 Dezember 2022, 18:26:33
1.) rytecDE_Basic wird bei dir 2 mal geladen. Einmal am Anfang der merge Funktion und dann noch einmal wenn du die Schleife durchläufst.

2.) Deine merge Funktion dürfte nicht mehr ohne $_filterChannels = 1 funktionieren.

3.) Es gibt auch anderssprachige Programmlisten, die würden mit deiner Variante nicht funktionieren, da du genau 3 Dateien in deiner merge Funktion zulässt.

Ich habe mal eine etwas andere Variante gestrickt...

  sub tvMerge\
  {\
    my ($dstName, @srcNames) = @_;;\
    my $fh;;\
    my $data;;\
    my $start = '';;\
    my $channels = '';;\
    my $channels_flt = '';;\
    my $programms = '';;\
    my $programms_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    if (-e $dstName)\
    {\
      open($fh, '<', $dstName) or die "Can't open file $!";;\
      read($fh, $data, -s $fh);;\
      close($fh);;\
\
      if (-1 != ($pos = index($data, '<channel ')))\
      {\
        $start = substr($data, 0, $pos);;\
      }\
\
      if (-1 != ($pos = rindex($data, '</programme>')))\
      {\
        $end = substr($data, $pos + 12);;\
      }\
\
      for (my $i = 0;; $i < (scalar(@srcNames) + 1);; $i++)\
      {\
        if (0 != $i)\
        {\
          my $file = $srcNames[$i - 1];;\
\
          if (-e $file)\
          {\
            open($fh, '<', $file) or die "Can't open file $!";;\
            read($fh, $data, -s $fh);;\
            close($fh);;\
          }\
          else\
          {\
            last;;\
          }\
        }\
\
        while ($data =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
        {\
          if (0 != $_filterChannels)\
          {\
            $_ = $1;;\
\
            if ($2 =~ $_channelFilter)\
            {\
              $channels_flt .= $_;;\
            }\
          }\
          else\
          {\
            $channels .= $1;;\
          }\
        }\
\
        while ($data =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
        {\
          if (0 != $_filterChannels)\
          {\
            $_ = $1;;\
\
            if ($2 =~ $_channelFilter)\
            {\
              $programms_flt .= $_;;\
            }\
          }\
          else\
          {\
            $programms .= $1;;\
          }\
        }\
      }\
\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (0 != $_filterChannels)\
      {\
        print $fh $start.$channels_flt.$programms_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels.$programms.$end;;\
      }\
\
      close($fh);;\
    }\
  }\


  sub tvDownloadMerge()\
  {\
    my $output = '';;\
\
    ## other server\
    ## http://www.xmltvepg.nl\
    ## http://91.121.106.172/~rytecepg/epg_data\
    ## http://rytecepg.epgspot.com/epg_data\
    ## http://epg.vuplus-community.net\
    ## datafiles: rytecDE_Basic.xz, rytecDE_Common.xz, rytecDE_SportMovies.xz\
    $output .= qx(wget $_server/rytecDE_Basic.xz -O $_path/rytecDE_Basic.xz 2>&1 || rm -f $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_Common.xz -O $_path/rytecDE_Common.xz 2>&1 || rm -f $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_Common.xz 2>&1);;\
    $output .= qx(wget $_server/rytecDE_SportMovies.xz -O $_path/rytecDE_SportMovies.xz 2>&1 || rm -f $_path/rytecDE_SportMovies.xz 2>&1);;\
    $output .= qx(xz -df $_path/rytecDE_SportMovies.xz 2>&1);;\
    ## download and merge other files here if needed\
\
    ## tvMerge($_dataFile, $_path.'/rytecDE_Common');;\
    tvMerge($_dataFile, $_path.'/rytecDE_Common', $_path.'/rytecDE_SportMovies');;\
\
    return $output;;\
  }\


tvMerge kann jetzt eine variable Anzahl von Übergabeparametern erhalten, die dann in der merge Funktion zusammen geführt werden. Intensivere Tests stehen noch aus, da ich das grad erst fertig gestellt habe. Deine Anregung doppelten Code zu entfernen ist aber tatsächlich sinnvoll, da es die Überschtlichkeit wesentlich erhöht. Das mit dem parsen schaue ich mir später auch noch mal an, da kann man, wie bei dir schon zu sehen, mit Sicherheit auch noch was kürzen.

Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 29 Dezember 2022, 22:26:41
1. Weiss ich, könnte man mit einer Abfrage lösen. Aufwand ist es aber so oder so.
2. Ja, habe ich ja geschrieben. Könnte man ganz löschen und über den Defaultwertl lösen.
3. Sollte eigentlich beliebig viele Dateien ermöglichen. Zumindest ist es so konzipiert. Falls nur drei gehen, ist das ein Fehler. ABER: ich habe nur drei Namen drin stehen, weil ich nur die drei kenne.

Zu deiner neuen Variante kann ich aktuell nichts sagen, am Handy kann man das nicht sinnvoll lesen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 30 Dezember 2022, 14:46:13
Interessanterweise habe ich mit Download und Merge keine Probleme, sondern mit Parse. Es werden nicht alle Sender abgefragt. Aber da verbergen sich ja auch noch die meisten der 20% ;).

Tante Edit hat den Fehler gefungen.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 01 Januar 2023, 19:04:25
Die Lernkurve *) war da, wie beim Walter zwei Schritte vor und einen zurück :D

Jetzt arbeitet das Script zu meiner Zufriedenheit. Aus optischen Gründen würde ich noch die Breite der Sender- und der Zeitspalten fest vergeben, dann kann man auch zwei Tabellen draus machen ("<") und sich die ganze Berechnung und Speicherung der Zeilenzahl sparen. Allerdings: "last" scheint nur im Wiki (https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#CSS-Variablen_und_Steuerungsattribute) zu existieren. Gibt man halt 100 ein, das reicht eine Weile.
Die Fehler beim Parsen und beim Aktualisieren der Anzeige sind behoben. Ein paar optische Kleinigkeiten (z.B. Platzhalter, wenn kein Mediathek und/oder Device-Eintag) noch und dann bin ich fertig.

*) unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc]) z.B. zeichnet die Tabelle dreimal neu, unfold("$2_$1_000") hingegen gar nicht. Meine Lösung: unfold("$2_$1_000",[$SELF:_$2_$1_000_1start]) was aber auch erfordert, dass dieses Reading nach den drei (im Original vier) anderen aktualisiert wird.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 02 Januar 2023, 10:46:29
Ich habe gestern mal etwas experimentiert und sobald ich etwas an der unfold Funktion ändere, werden Updates gar nicht mehr oder nur unvollständig angezeigt. Zu sehen ist das, wenn man sich eine zu ändernde Sendung raus sucht und dann auf das 5min Raster wartet. Wenn man da rum spielt, ist danach der Titel oder die Description falsch. Man muss also alle Dinge updaten. Zudem wird, meines Erachtens, nicht die ganze Tabelle neu gezeichnet, sondern nur die Zelle bzw. deren Inhalt.

Eventuell kann man damit aber noch Experimentieren: https://fhem.de/commandref_DE.html#DOIF_Zeitintervalle_Readings_und_Status_ohne_Trigger (https://fhem.de/commandref_DE.html#DOIF_Zeitintervalle_Readings_und_Status_ohne_Trigger)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 02 Januar 2023, 11:36:46
Updaten musst du natürlich alle, aber nur die letzte in der (zeitlichen) Reihe muss triggern.
Gestern kam aber z.B. eine Sendung auf RTL2 (?, "Shopping Queen"), da hatten (mind.) 3 Folgen den gleichen Titel, Subtitel und die gleiche Beschreibung.
Ergo: kein Trigger bei event-on-change-reading. Die Reit ändert sich aber immer. Wobei es ja kein Problem ist, wenn sich ohnehin nichts ändert, aber wenn man nur auf eins davon triggert und das falsche erwischt? Ich triggere auf die Startzeit und aktualisiere das Reading als letztes, dann passt das immer.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 02 Januar 2023, 13:16:58
Und wenn alles gleich ist, warum muss man dann triggern?

PS: Hier gibt es übrigens auch noch ein ganz nettes Programmpaket, allerdings sieht es so aus, als ob man sich das täglich downloaden müsste. https://iptv-org.github.io/ (https://iptv-org.github.io/)
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 03 Januar 2023, 00:00:09
Interessant, aber dann sitze ich nur noch vorm PC :D

Das tägliche Downloaden wäre doch mit Fhem gar kein Problem...
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 03 Januar 2023, 18:51:57
Ich habe jetzt im ersten Beitrag meine vorerst finale Version abgelegt. Hier habe ich noch die Anzahl der Readings auf 3 von ursprünglich 5 pro Eintrag reduziert. In der Version von Per waren bereits Date und Time zu einem Reading zusammen geführt worden, was ich auch übernommen habe. Zusätzlich dazu habe ich noch stitle und desc zusammengeführt.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 03 Januar 2023, 19:10:00
Letzteres hatte ich auch überlegt, aber da dort ein <br> als Trenner reinkommt, dürfte der (optische) Platzbedarf sich nicht verkleinern.
defmod TV_Programm DOIF subs\
{\
  \
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  $_name = "$SELF";;\
  $_path = qx(pwd 2>&1);;\
  $_path =~ s/\/?\s/\//;;\
  #'/opt/fhem/';;\
  $_data = '/rytecDE_filt_'.$_name;;\
  $_dataFile = $_path.$_data;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  $_server = AttrVal($_name,"server","http://epg.vuplus-community.net");; \
  my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
  $channelFilter =~ s/\|$//;;\
  $_channelFilter = qr/^(?:$channelFilter)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
\
  sub filterText($)\
  {\
    my $text = shift;;\
    \
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
    \
    return $text;;\
  }\
\
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
    \
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
      \
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
\
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs)\
    {\
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
      \
      $telnet = $d;;\
      last;;\
    }\
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
      \
      if (defined($ret))\
      {\
        Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
      \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub sendTelnet($$)\
  {\
    my ($name, $sendTelnet) = @_;;\
    if ($sendTelnet)\
    {\
      my $port;;\
      $port = createTelnet($name);;\
      $port = $_telnetPort if (!defined($port));;\
      `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
    }\
  }\
\
  sub DOIF::doDownload($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    my $output = '';;\
    $output .= qx(wget $_server/$data.xz -O $_path/$data.xz 2>&1);;\
    $output .= qx(xz -df $_path/$data.xz 2>&1);;\
    \
    return $name.'|'. $data.'|'.$output;;\
  }\
\
  sub DOIF::endDownload($)\
  {\
    my ($name, $data, $output) = split("\\|", shift);;\
    \
    Log3 $name, 5, $name.': '.$output;;\
    Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    my $blockname = "PID_DOWNLOAD".$data;;\
    delete($_blockingcalls{$blockname});;\
    $_lastdown = time();;\
    sendTelnet($name,";;setreading $name $data $_lastdown;;");;\
  }\
\
  sub DOIF::abortDownload($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    \
    my $blockname = "PID_DOWNLOAD".$data;;\
    delete($_blockingcalls{$blockname});;\
    Log3 $name, 1, $name.': Blocking call aborted (download).';;\
    $_lastdown = 0;;\
    sendTelnet($name,";;setreading $name $data $_lastdown;;");;\
  }\
\
  sub startDownload($)\
  {\
    my $fileName = shift;;\
    my $dataFile = $_path.$fileName;;\
    \
    # prevent download spamming\
    if (-e $dataFile)\
    {\
      my $btime = ((time() - (stat($dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      \
      if ($btime < 1.0)\
      {\
        Log3 $_name, 1, $_name.': Download of '.$fileName.' skipped because file is not older than 1 day ('.($btime).').';;\
        return;;\
      }\
    }\
    \
    my $blockname = "PID_DOWNLOAD".$fileName;;\
    if (defined($_blockingcalls{$blockname}))\
    {\
      Log3 $_name, 3, $_name.': Blocking call already running (download).';;\
      ::BlockingKill($_blockingcalls{$blockname});;\
    }\
    \
    $_blockingcalls{$blockname} = ::BlockingCall('DOIF::doDownload', $_name.'|'.$fileName, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $_name.'|'.$fileName);;\
  }\
\
  sub DOIF::doMerge($)\
  {\
    my ($name, $data) = split("\\|", shift);;\
    my $output = '';;\
    \
    my @srcName = ('rytecDE_Basic','rytecDE_Common','rytecDE_SportMovies');;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels = '';;\
    my $programms = '';;\
    my $end = '';;\
    my $pos;;\
    my $ftime = 2;;\
    \
    open($fh, '<', $_path.$srcName[0]) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
    \
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
    \
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
    \
#    if (0 != $_filterChannels)\
    {\
      my $FilesCount = (@srcName);;\
      for ($i=0;;$i<$FilesCount;;$i++)\
      {\
$src = $srcName[$i];;\
if (-e $src)\
{\
          open($fh, '<', $src) or die "Can't open file $!";;\
          read($fh, $src, -s $fh);;\
          close($fh);;\
          while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
          {\
            $_ = $1;;\
            \
            if ($2 =~ $_channelFilter)\
            {\
              $channels .= $_;;\
            }\
          }\
          \
          while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
          {\
            $_ = $1;;\
            \
            if ($2 =~ $_channelFilter)\
            {\
              $programms .= $_;;\
            }\
          }\
        }\
      }\
    }\
    open($fh, '>', $_dataFile) or die "Can't open file $!";;\
    print $fh $start.$channels.$programms.$end;;\
    close($fh);;\
    \
    return $name.'|'.$output;;\
  }\
\
  sub DOIF::endMerge($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    Log3 $name, 5, $name.': '.$output;;\
    Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_MERGE});;\
    $_lastmerge = time();;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
  }\
\
  sub DOIF::abortMerge($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_MERGE});;\
    \
    Log3 $name, 1, $name.': Blocking call aborted (download).';;\
    $_lastmerge = 0;;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
  }\
\
  sub startMerge($)\
  {\
    my $name = shift;;\
    \
    my $channelFilter = ReadingsVal($_name,"sender","ZDF\\.|");;\
    $channelFilter =~ s/\|$//;;\
    $_channelFilter = qr/^(?:$channelFilter)/;;\
    \
    if (defined($_blockingcalls{PID_DOWNLOADrytecDE_Basic})\
    or defined($_blockingcalls{PID_DOWNLOADrytecDE_Common})\
    or defined($_blockingcalls{PID_DOWNLOADrytecDE_SportMovies}))\
    {\
      set_Exec('init_merge', 10, 'startMerge("$SELF")');;\     
      return;;\
    }\
    if (defined($_blockingcalls{PID_MERGE}))\
    {\
      Log3 $name, 3, $name.': Blocking call already running (merge).';;\
      \
      ::BlockingKill($_blockingcalls{PID_MERGE});;\
    }\
    \
    $_lastmerge = 0;;\
    sendTelnet($name,";;setreading $name lastmerge $_lastmerge;;");;\
    \
    $_blockingcalls{PID_MERGE} = ::BlockingCall('DOIF::doMerge', $name.'|'.$_data, 'DOIF::endMerge', 300, 'DOIF::abortMerge', $name);;\
  }\
\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $n = 999;;\
    my $p = 999;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $nextparse = time() + 3600;;\
    my $start;;\
    my $stop;;\
    my $startform;;\
    my $readingValue;;\
    my $old = time() + $_timeAdjust;;\
    \
    ## check if any update is needed\
    if ((0 != $_updateBasedOnStarttimes) && ('prime' ne $mode) && keys(%{$_startTimes}))\
    {\
      my $nothingTodo = 1;;\
      foreach (keys(%{$_startTimes}))\
      {\
        if ($_startTimes{$_} <= $old)\
        {\
          $nothingTodo = 0;;\
          Log3 $device, 4, $device.': Update is not blocked because at least one actual program is finished (reading: '.$_.', start: '.$_startTimes{$_}.', old: '.$old.').';;\
          last;;\
        }\
      }\
      \
      if (0 != $nothingTodo)\
      {\
        Log3 $device, 4, $device.': Update is blocked because no actual program was finished.';;\
        return %{$_startTimes};;\
      }\
    }\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
    \
    if (!$@)\
    {\
      \
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
        \
           # filter old stuff\
        if ($stop > $old)\
        {\
          if ($lastChannel ne $_->{'channel'}{'value'})\
          {\
            $lastChannel = $reading = $_->{'channel'}{'value'};;\
            $reading =~ s/[\.\s]//g;;\
            $reading =~ s/de$//;;\
            $p = 0;;\
    \
            $nextparse = $stop if (($nextparse > $stop) and ($stop > (time() + 30)));;\
            if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
            {\
              $n = 0;;\
      $_startTimes{$reading} = $stop if (0 != $_updateBasedOnStarttimes);;\
            }\
            else\
            {\
            Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (reading: '.$reading.', start: '.$_startTimes{$reading}.', old: '.$old.').';;\
#              Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
            }\
          }\
  \
          $start = xmltv2epoch($_->{'start'}{'value'});;\
      $startform = substr(FmtDateTime($start), 0, 19);;\
  \
          if (($p < 3 && 'prime' eq $mode && $startform gt $primeTime) or ($n < 3 && 'next' eq $mode))\
          {\
            my $setreading = ";;setreading $device _$reading";;\
    my $sendTelnet = '';;\
    if ('prime' eq $mode)\
    {\
              $setreading .= "_prime_".sprintf("%03d", $p++);;\
    }\
    else\
    {\
              $setreading .= "_next_".sprintf("%03d", $n++);;\
    }\
    \
            $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
            $sendTelnet .= $setreading."_2title $readingValue";;\
    \
            $readingValue = ((exists($_->{'sub-title'}{'value'})) ? filterText($_->{'sub-title'}{'value'}) : 'na');;\
            $sendTelnet .= $setreading."_3stitle $readingValue";;\
    \
            $readingValue = ((exists($_->{'desc'}{'value'})) ? filterText($_->{'desc'}{'value'}) : 'na');;\
            $sendTelnet .= $setreading."_4desc $readingValue";;\
    \
            $readingValue = $startform;;\
            $sendTelnet .= $setreading."_1start $readingValue";;\
    \
              #Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
            \
            `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
            \
          }\
        }\
      }\
      \
      if ('next' eq $mode)\
      {\
my $sendTelnet .= ";;setreading $device nextparse ". ($nextparse - time() + 10);;\
         #Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
\
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name.'|'.$mode;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
\
  sub DOIF::endParse($)\
  {\
    my ($name, $mode, @newStartTimes) = split("\\|", shift);;\
    \
    for (my $i = 0;; $i < scalar(@newStartTimes);; $i += 2)\
    {\
      $_startTimes{$newStartTimes[$i]} = $newStartTimes[$i + 1];;\
    }\
    \
    Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    my $testparse = "PID_PARSE".$mode;;\
    delete($_blockingcalls{$testparse});;\
  }\
\
  sub DOIF::abortParse($)\
  {\
    my ($name, $mode) = split("\\|", shift);;\
    \
    Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
    \
    my $testparse = "PID_PARSE_".$name.$mode;;\
    delete($_blockingcalls{$testparse});;\
  }\
\
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    \
    if (defined($_blockingcalls{PID_MERGE}))\
    {\
      return;;\
    }\
    my $testparse = "PID_PARSE_".$name.$mode;;\
    if (defined($_blockingcalls{$testparse}))\
    {\
      Log3 $name, 3, $name.': Blocking call already running (parse).';;\
      ::BlockingKill($_blockingcalls{$testparse});;\
    }\
    \
    my $port;;\
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{$testparse} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name.'|'.$mode);;\
  }\
}\
\
init\
{\
  fhem("set $SELF down");;\
  if ([?$SELF:nextparse:sec] > 86400)\
  {\
    set_Exec('init_merge', 20, 'startMerge("$SELF")');;\
  }\
  else\
  {\
    set_Exec('init_next', 20, 'startParse("$SELF", "next")');;\
  }\
  set_Exec('init_next_sik', 7200, 'startParse("$SELF", "next")');;\
}\
down\
{\
  [00:05|Mo Do];;\
  set_Exec('init_down_Basic', 1, 'startDownload("rytecDE_Basic")');;\
  set_Exec('init_down_Common', 2, 'startDownload("rytecDE_Common")');;\
#  set_Exec('init_down_Sport', 3, 'startDownload("rytecDE_SportMovies")');;\
}\
merge\
{\
  [01:05|Mo Do];;\
  set_Exec('init_merge', 10, 'startMerge("$SELF")');;\
}\
parse_next_manu\
{\
  [$SELF:lastmerge];;\
  set_Exec('init_next', 20, 'startParse("$SELF", "next")');;\
}\
parse_next\
{\
  set_Exec('init_next', [$SELF:nextparse], 'startParse("$SELF", "next")');;\
  set_Exec('init_next_sik', 3601, 'startParse("$SELF", "next")');;\
}\
parse_prime\
{\
  [00:30];;\
  [$SELF:lastmerge];;\
  set_Exec('init_prime', 30, 'startParse("$SELF", "prime")');;\
}\
_refill\
{\
#  if ([$SELF:sender])\
  {\
    if (ReadingsVal("$SELF","sender","ZDF\\.") ne $_Senderliste)\
    {\
      fhem("deletereading $SELF .*(next|prime)_.*  200000");;\
      fhem("setreading $SELF sender $_Senderliste");;\
      fhem("set $SELF down");;\
      set_Exec('init_merge', 20, 'startMerge("$SELF")');;\
    }\
    fhem("setreading $SELF rowsnext $_rowsnext");;\
    fhem("setreading $SELF rowsprime $_rowsprime");;\
    \
  }\
}
attr TV_Programm userattr server:http://epg.vuplus-community.net,http://www.xmltvepg.nl,http://91.121.106.172/~rytecepg/epg_data,http://www.vuplus-community.net/rytec
attr TV_Programm alias Aktuelles TV-Programm
attr TV_Programm event-on-change-reading .*
attr TV_Programm event-on-update-reading nextparse
attr TV_Programm room Wohnzimmer
attr TV_Programm server http://www.xmltvepg.nl
attr TV_Programm uiTable\
{\
  package ui_Table;;\
  \
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  my $rowsnext = 100;; ##::ReadingsVal("$SELF","rowsnext",0);;\
  my $rowsprime = 100;; ##::ReadingsVal("$SELF","rowsprime",0);;\
  my $lastrow = 105;; ##$rowsnext + $rowsprime + 2;;\
  \
  $TR{0} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px;;'";;\
  $TR{($rowsnext + 2)} = "style='color:red;;text-align:center;;font-weight:bold;;font-size:18px;;'";;\
  $TR{1..($rowsnext),($rowsnext + 4)..$lastrow} = "style='font-size:16px'";;\
  $TR{($rowsnext + 1)} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
#  $TD{0..$lastrow}{0} = ##"align='center'";;\
  $TD{0..$lastrow}{0} = "style='width:150px;;'";;\
  $TD{0..$lastrow}{2} = "style='width:22px;;'";;\
  $TD{0..$lastrow}{1,4,6} = "style='width:50px;;'";;\
  $TD{0..$lastrow}{3,5,7} = "style='width:25%;;'";;\
  $TD{0..$rowsnext, ($rowsnext + 3)..$lastrow}{1,4,6} = "style='border-left-style:solid;;border-color:#CCCCCC;;border-left-width:1px;;'";;\
  \
  sub showIcon\
  {\
    my ($mode, $icon, $show, $device, $state) = @_;;\
    $_rowsprime_temp += ($mode eq "prime" ? 1 : 0);;\
    $_rowsnext_temp += ($mode eq "next" ? 1 : 0);;\
    $_Senderliste_temp =~ s/$icon\\.\|//;;\
    $_Senderliste_temp .= $icon . "\\.|";;\
    \
    if ($device && $state)\
    {\
      return "<a href=\"". ::ReadingsVal("$SELF","$device","") =~ s/.state/$state/r ."\" target=\"IPTV\">".ICON("$show")."</a>";;\
#      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      if ($device)\
      {\
        return ICON("$show")."</td><td>"."<a href=\"$device\" target=\"IPTV\">".ICON("tv/20px-Icon-video-library")."</a> ";;\
      }\
      else\
      {\
        return ICON("$show");;\
      }\
    }\
  }\
\
  sub unfold\
  {\
    my ($ReadingPre,$akt) = @_;;\
    my $title = ::ReadingsVal("$SELF","_${ReadingPre}_2title","-");;\
    my $desc = ::ReadingsVal("$SELF","_${ReadingPre}_3stitle","na")."\n\n". ::ReadingsVal("$SELF","_${ReadingPre}_4desc","na") ;;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/g;;\
    $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/[\r\'\"]/ /g;;\
    $desc =~ s/[\n]|\\n/<br>/g;;\
#    my $href = ($link ? "<a href=\"$link\" target=\"IPTV\">".ICON("tv/20px-Icon-video-library")."</a>" : "");;\
    return "<a href=\"#!\" onclick=\"FW_okDialog(';$title<br>$desc';)\">$title</a>";;\
  }\
\
  sub MT\
  {\
    my ($link) = @_;;\
    return "<a href=\"$link\" target=\"IPTV\">".ICON("tv/20px-Icon-video-library")."</a>" ;;\
  }\
\
  sub vars_reset\
  {\
    $_Senderliste_temp = "";; $_rowsprime_temp = 0;;$_rowsnext_temp = 0;;return "Sender";;\
  }\
\
  sub vars_save\
  {\
    $_Senderliste = $_Senderliste_temp;;\
    $_rowsprime = $_rowsprime_temp;;\
    $_rowsnext = $_rowsnext_temp;;\
    return ;;\
  }\
}\
##\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$1", "$2", "$3", "$4", "$5")|substr([$SELF:_$2_$1_000_1start],11,5)|unfold("$2_$1_000",[$SELF:_$2_$1_000_1start])|substr([$SELF:_$2_$1_001_1start],11,5)|unfold("$2_$1_001",[$SELF:_$2_$1_000_1start])|substr([$SELF:_$2_$1_002_1start],11,5)|unfold("$2_$1_002",[$SELF:_$2_$1_002_1start]))\
##\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$1", "$2", "$3")|substr([$SELF:_$2_$1_000_1start,"01234567890  -  "],11,5)|" "|unfold("$2_$1_000",[$SELF:_$2_$1_000_1start,"01234567890  -  "])|substr([$SELF:_$2_$1_001_1start,"01234567890  -  "],11,5)|unfold("$2_$1_001",[$SELF:_$2_$1_001_1start,"01234567890  -  "])|substr([$SELF:_$2_$1_002_1start,"01234567890  -  "],11,5)|unfold("$2_$1_002",[$SELF:_$2_$1_002_1start]))\
##\
## parameter: mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), URL Mediathek\
DEF TPL_TVMT(showIcon("$1", "$2", "$3")|substr([$SELF:_$2_$1_000_1start,"01234567890  -  "],11,5)|MT("$4")|unfold("$2_$1_000",[$SELF:_$2_$1_000_1start,"01234567890  -  "])|substr([$SELF:_$2_$1_001_1start,"01234567890  -  "],11,5)|unfold("$2_$1_001",[$SELF:_$2_$1_001_1start,"01234567890  -  "])|substr([$SELF:_$2_$1_002_1start,"01234567890  -  "],11,5)|unfold("$2_$1_002",[$SELF:_$2_$1_002_1start]))\
##\
DEF TPL_START(vars_reset()|"ab"|" "|"Aktuelle Sendung"|"ab"|"N&auml;;chste Sendung"|"ab"|"Sendung")\
DEF TPL_END(vars_save())\
##\
TPL_START()\
TPL_TVMT(next,DasErste,01 ARD,https://www.ardmediathek.de/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL2xpdmUvY2xpcC9hYmNhMDdhMy0zNDc2LTQ4NTEtYjE2Mi1mZGU4ZjY0NmQ0YzQ)\
TPL_TVMT(next,ZDF,02 ZDF,https://www.zdf.de/live-tv)\
TPL_TV(next,RTL,04 RTL)\
TPL_TV(next,RTL2,05 RTL2)\
TPL_TV(next,Vox,06 Vox)\
TPL_TV(next,VOXup,.. VOXup)\
TPL_TVMT(next,ProSieben,07 ProSieben,https://video.prosieben.de/livestreams/1)\
TPL_TVMT(next,Sat1,08 Sat1,https://video.prosieben.de/livestreams/2)\
TPL_TVMT(next,KabelEins,09 KabelEins,https://video.prosieben.de/livestreams/3)\
TPL_TVMT(next,3sat,10 3Sat,https://www.ardmediathek.de/live/Y3JpZDovLzNzYXQuZGUvTGl2ZXN0cmVhbS0zc2F0)\
TPL_TVMT(next,ARTE,11 Arte,https://www.ardmediathek.de/live/Y3JpZDovL2FydGUuZGUvTGl2ZXN0cmVhbS1BUlRF)\
TPL_TV(next,DMax,12 D-Max)\
TPL_TVMT(next,ServusHD,13 ServusTV,https://www.servustv.com/allgemein/p/jetzt-live/119753/)\
TPL_TVMT(next,NDRFernsehen,14 NDR,https://www.ardmediathek.de/live/Y3JpZDovL25kci5kZS9MaXZlc3RyZWFtLU5EUi1OaWVkZXJzYWNoc2Vu)\
TPL_TVMT(next,WDRFernsehen,15 WDR3,https://www.ardmediathek.de/live/Y3JpZDovL3dkci5kZS9CZWl0cmFnLTNkYTY2NGRlLTE4YzItNDY1MC1hNGZmLTRmNjQxNDcyMDcyYg)\
TPL_TVMT(next,HRFernsehen,16 HR3,https://www.ardmediathek.de/live/Y3JpZDovL2hyLmRlL0xpdmVzdHJlYW0tSFI)\
TPL_TVMT(next,SWRFernsehen,17 SWR,https://www.ardmediathek.de/live/Y3JpZDovL3N3ci5kZS8xMzQ4MTA0Mg)\
TPL_TVMT(next,MDRS-Anhalt,18 MDR,https://www.ardmediathek.de/live/Y3JpZDovL21kci5kZS9MaXZlc3RyZWFtLU1EUi1TYWNoc2Vu)\
TPL_TVMT(next,BRFernsehen,BR3,https://www.ardmediathek.de/live/Y3JpZDovL2JyLmRlL0xpdmVzdHJlYW0tQlItU8O8ZA)\
TPL_TVMT(next,rbbBerlin,RBB,https://www.ardmediathek.de/live/Y3JpZDovL3JiYi1vbmxpbmUuZGUvcmJiZmVybnNlaGVuL2xpdmVfYnJhbmRlbmJ1cmcvc2VuZGVwbGF0ei0tLWxpdmVzdHJlYW0tLS1icmFuZGVuYnVyZy0tLWhsczE)\
TPL_TV(next,ComedyCentralVIVA,19 ComedyCentral)\
TPL_TVMT(next,ProSiebenMaxx,20 pro7maxx,https://video.prosieben.de/livestreams/5)\
TPL_TV(next,SuperRTL,21 SuperRTL)\
TPL_TV(next,RTLNitro,22 Nitro)\
TPL_TVMT(next,Tele5,23 Tele5,https://tele5.de/live/)\
TPL_TVMT(next,Sat1Gold,24 Sat1 Gold,https://video.prosieben.de/livestreams/6)\
TPL_TVMT(next,phoenix,25 phoenix,https://www.ardmediathek.de/live/Y3JpZDovL3Bob2VuaXguZGUvTGl2ZXN0cmVhbS1waG9lbml4)\
TPL_TVMT(next,KabelEinsDoku,202 Kabel1doku,https://video.prosieben.de/livestreams/7)\
TPL_TV(next,N24Doku,203 n24 Doku)\
TPL_TVMT(next,ZDFinfo,204 ZDF Info,https://www.zdf.de/live-tv)\
TPL_TV(next,Sport1HD,300 DSF)\
TPL_TV(next,Eurosport1,301 Eurosport)\
TPL_TV(next,WELT,302 Welt n24)\
TPL_TVMT(next,ntv,303 n-tv,https://www.n-tv.de/mediathek/livestream/24-Stunden-ntv-Livestream-article9511936.html)\
TPL_TVMT(next,tagesschau24,304 tagesschau24,https://www.ardmediathek.de/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL3RhZ2Vzc2NoYXUvbGl2ZXN0cmVhbQ)\
TPL_TVMT(next,History,history,https://www.history.de/history-play/history-play-auf-amazon-prime.html)\
TPL_TV(next,TLC,TLC)\
TPL_TVMT(next,Sixx,?? Sixx,https://video.prosieben.de/livestreams/4)\
TPL_TV(next,HGTV,428 HGTV)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"<\
"Sender"|"ab"|" "|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV(prime,DasErste,ard)\
TPL_TV(prime,ZDF,zdf)\
TPL_TV(prime,Sat1,sat1)\
TPL_TV(prime,RTL,rtl)\
TPL_TV(prime,RTL2,rtl2)\
TPL_TV(prime,ProSieben,pro7)\
TPL_TV(prime,DMax,dmax)\
TPL_TV(prime,Vox,vox)\
TPL_TV(prime,KabelEins,kabel1)\
TPL_TV(prime,KabelEinsDoku,kabel1doku)\
TPL_TV(prime,KabelEinsClassic,kabel1classic)\
TPL_TV(prime,ProSiebenMaxx,pro7maxx)\
TPL_TV(prime,Sixx,sixx)\
TPL_TV(prime,ntv,ntv)\
TPL_TV(prime,N24Doku,n24)\
TPL_TV(prime,History,history)\
TPL_TV(prime,TLC,tlc)\
TPL_END()


Hier sind zwar noch die Berechnungen für die einzelnen Tabellenteile drin, genutzt werden sie aber nicht wirklich, weil die Tabelle bei mir zweigeteilt ist. Ob gut oder schlecht, die Breite der Spalten ist dafür fixiert.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 09 Januar 2023, 19:58:14
Ich habe den Link im ersten Beitrag angepasst. Könntest du bei Änderungen vielleicht deinen aktuell letzten Beitrag editieren bitte? Dann muss ich nicht jedes Mal den Link aktualisieren. Wenn ich zu deiner Version noch etwas dazu schreiben soll, dann lass es mich bitte wissen und ich schreibe es dazu.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 10 Januar 2023, 14:27:17
Aktuell kommt von mir jetzt weniger, weil ich erstmal Grundlagen (Wirkbereiche von Variablen, Ansprechen von Variablen, Syntax dafür u.a.) "studiere". Zwei Devices haben mir noch zu viele Wechselwirkungen.
Aber die Idee mit dem festen Link ist gut, da finde ich es auch eher ;) und der Board Server ist (etwas) weniger belastet.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Damian am 10 Januar 2023, 22:34:13
Was mir gerade noch aufgefallen ist:

{\
  if ([00:00:30|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
\
  if ([+:05])\
  {\
    ## start in a raster of 5min\
    startParse("$SELF", 'next');;\
  }\
\
  if ([00:32:30])\
  {\
    ## start between next updates\
    startParse("$SELF", 'prime');;\
  }\
}


sollte besser in einzelne Blöcke aufgeteilt werden. So wird der ganze Block alle 5 Minuten unnötig mit allen drei ifs abgearbeitet.

besser:

{
  if ([00:00:30|Mo Do])
  {
    startDownload("$SELF");
  }
}
{
  if ([+:05])
  {
    ## start in a raster of 5min
    startParse("$SELF", 'next');
  }
}
{
  if ([00:32:30])
  {
    ## start between next updates
    startParse("$SELF", 'prime');
  }
}


noch besser

{[00:00:30|Mo Do];startDownload("$SELF")}
{[+:05];startParse("$SELF", 'next')}
{[00:32:30];startParse("$SELF", 'prime')}


Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 11 Januar 2023, 21:44:02
Ziehe ich die nächsten Tage gerade. Vielen Dank für die Information!!!

Ich habe auch noch eine Option eingebaut (ein- und ausschaltbar), das alle Daten im RAM gehalten werden, dann fällt das Laden und Parsen der XML Datei alle 5min auch noch weg... Das Laden der Datei ist dann aber leider blocking, allerdings auch nur genau 2x die Woche um 0:30 Uhr.
Titel: Antw:Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 15 Januar 2023, 11:56:43
Version im 1. Beitrag wurde aktualisiert. Neben der von Damian vorgeschlagenen Änderung ist eine Option enthalten, die Downloaddaten komplett im RAM zu halten und sich so das laden der Datei alle 5min zu sparen. Die Variante hat allerdings den Nachteil, das der Vorgang alle 3 Tage gegen 0:30 Uhr blocking ausgeführt wird. Hier muss der Anwender selbst entscheiden, ob er das möchte (Default: ausgeschaltet).
Titel: Aw: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 24 Juli 2023, 21:05:15
Die Performance wurde noch einmal massiv erhöht bzw. die Systembelastung verringert.
Titel: Aw: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 24 Juli 2023, 23:31:59
Wo zu finden?
Titel: Aw: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 25 Juli 2023, 00:18:32
Wie immer wurde der erste Beitrag aktualisiert.
Titel: Aw: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: Per am 01 November 2023, 12:10:38
Ich habe jetzt nicht den Anhang runter geladen, sondern den getagten Code gelesen: Du könntest noch, falls im Anhang noch nicht geschehen, ReadingsVal("$SELF",... durch get_Reading(... ersetzen. Das eird gerade im Anzeigeteil relativ oft aufgerufen.
Titel: Aw: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)
Beitrag von: mumpitzstuff am 01 November 2023, 12:29:38
Das finde ich eigentlich nur 1x in einem Teil (Code aus dem ersten Beitrag), den ich normalerweise nicht verwende. Man müsste showIconIp selbst aktivieren.