#!/usr/bin/perl

#
# Upgrade database mysql for internal playlist sorage and dynamic update
# 1. expanding field that is not used for iptv     - SQL:alter table channel MODIFY freqid varchar(255);
# 2. Add a new option (flag) to the table settings - SQL:insert into settings (value,data) VALUES('iptv_playlist_change','1');
# 3. Choose the type of card - FREEBOX (Network Recorder) in the M3U URL prescribes intrenal:KEYWORD
#    option says that the internal library to take out the base, KEYWORD can be of any, this is usually the provider name
#    it must coincide with the set variable $ IPTV_SOURCE in mythchannel_sync
#
# Подготовка базы mysql для внутреннего хранения плейлиста и динамического обновления
# 1. расширяем поле которое не использьуется в iptv  - SQL:alter table channel MODIFY freqid varchar(255);
# 2. Добавляем новую опцию (флаг) в таблицу settings - SQL:insert into settings (value,data) VALUES('iptv_playlist_change','1');
# 3. Выбираем тип карты - FREEBOX (Сетевой рекордер) в поле M3U URL прописываем intrenal:KEYWORD
#    опция internal говорит что плейлист брать из базы, KEYWORD может быть любым это имя провайдера оно должно совпадать 
#    с установленной переменной $IPTV_SOURCE в mythchannel_sync

# Run this script periodically

#
# Playlist format:
# csv
# CHID\tCHNOMER\tXMLTVID\tURLICON\tCHNAME\tCHURL\n
# ...

# examlpe
# 123\t1\t345\thttp://serv.com/image/img.gif\tSuper Channel\tudp://230.0.0.1:1234\n

# PS You can easily modify

use Socket;
use DBI;
use Encode;
use encoding "utf8";

$DEBUG=1;
#######################################################
$IPTV_SOURCE="myiptvisp";
$PLAYLIST_URL="http://serv.com/playlist.php";
#######################################################
$DB_HOST="localhost";
$DB_PORT="0";
$DB_NAME="mythtv";
$DB_USER="user";
$DB_PASS="pass";
$HOME_DIR="/home/localuser"; # dir .mythtv/channels
#######################################################


# забираем playlist
($type,$file,$buf)=http_get($PLAYLIST_URL);
@chlist=split(/\n/,$buf);
unless ($chlist[0] =~ /^csv/i) { exit; }


# формируем плейлист и закачиваем отсутствующие иконки
foreach $ch (@chlist)
{
  $ch=~s/[\r\n]//g;
  $type='';
  ($chid,$chno,$tvpid,$icon,$name,$url)=split(/\t/,$ch);

  if ($url eq "") { next; }

  if ($icon ne '')
  {
    ($a1,$a2,$a3,$file)=parse_url($icon);
    $full_icon="$HOME_DIR/.mythtv/channels/$file";
    unless (-e $full_icon)
    {
      ($type,$file,$buf)=http_get($icon);
    }

    if ($type=~/image/i)
    {
      open(F,">",$full_icon);
      print F $buf;
      close F;
    }
    #$icon=$file; # mythtv сам знает в какой директории лежат иконки
    $icon=$full_icon; # лучше указать полный путь некоторые элементы не видят иконки
  }

  $CHLIST_NEW{$chid}->{'chno'}=$chno;
  $CHLIST_NEW{$chid}->{'tvpid'}=$tvpid;
  $CHLIST_NEW{$chid}->{'icon'}=$icon;
  $CHLIST_NEW{$chid}->{'name'}=$name;
  $CHLIST_NEW{$chid}->{'url'}=$url;
}

# Флаг изменения
$DB_CHANGE=0;

# подключаемся к БД
my $dbh = DBI->connect("DBI:mysql:database=$DB_NAME;host=$DB_HOST",$DB_USER,$DB_PASS,{'RaiseError' => 0}) or die "Can`t connect to MySQL!\n";

# устанавливаем кодировку
$dbh->{'mysql_enable_utf8'} = 1;
$dbh->do("set character set utf8");
$dbh->do("SET NAMES 'utf8'");

# узнаем id видеоисточника
$hl=$dbh->prepare("SELECT i.sourceid FROM capturecard AS c,cardinput AS i WHERE c.cardtype='FREEBOX' AND c.videodevice='internal:$IPTV_SOURCE' AND c.cardid=i.cardid GROUP BY 1");
$hl->execute();
($SOURCE_ID)=$hl->fetchrow_array();
$hl->finish();

if ($SOURCE_ID eq "") { die "Can`t find cardtype: FREEBOX and/or videodevice(M3U URL): internal:$IPTV_SOURCE \n"; }

print "Select sourceid: $SOURCE_ID\n";


$CH_DELETE=0;
$CH_UPDATE=0;
$CH_INSERT=0;


# выводим все каналы для этого видео источника
$hl=$dbh->prepare("SELECT chanid,channum,freqid,callsign,name,icon,xmltvid,visible FROM channel WHERE sourceid='$SOURCE_ID'") or die "Can`t select 1\n";
$hl->execute();
do {
while ( ($id,$chno,$url,$chid,$name,$icon,$tvpid,$visible)=$hl->fetchrow_array() )
{
#  print "$id $name $icon\n";

  # канал был удален
  if ( !defined($CHLIST_NEW{$chid}) )
  {
    $dbh->do("DELETE FROM channel WHERE callsign='$chid'");
    $CH_DELETE++;
    $DB_CHANGE=1;
print "- $url $name\n" if ($DEBUG);
    next;
  }

  # канал присутствует, проверяем на изменения ...
  $CH=$CHLIST_NEW{$chid};
  ($chno_n,$tvpid_n,$icon_n,$name_n,$url_n) = @{$CH}{ ('chno','tvpid','icon','name','url') };
#print "$name_n\n";
  # проверка на пеенумерацию mythtv -> iptv
  #if ( $chno_n ne $chno ) {}  # пока не очень ясно как это делать по идее надо зарание перед этим циклом сделать все изменения а потом в этом цикле все принять

  if    ( $url_n   ne $url   ) { $change=1; }
  elsif ( $chno_n  ne $chno  ) { $change=1; }
  elsif ( $tvpid_n ne $tvpid ) { $change=1; }
  elsif ( $name_n  ne $name  ) { $change=1; }
  elsif ( $icon_n  ne $icon  ) { $change=1; }
  else                         { $change=0; }

  # удаляем из списка этот канал
  delete($CHLIST_NEW{$chid});

  # если изменений нет пропускаем обработку этого канала
  unless ($change) { next; }

  $CH_UPDATE++;
  $DB_CHANGE=1;
print "! $url_n $name_n\n" if ($DEBUG);
  $dbh->do("UPDATE channel SET channum='$chno_n',freqid='$url_n',name='$name_n',icon='$icon_n',xmltvid='$tvpid_n' WHERE chanid='$id'");
}
} while ($hl->more_results);
$hl->finish();


# узнаем максимальный id канала
$hl=$dbh->prepare("SELECT max(chanid) FROM channel");
$hl->execute();
($CHANID_LAST)=$hl->fetchrow_array();
$hl->finish();


# всавляем оставшиеся каналы в списке, это новые каналы
while ( ($chid,$CH) = each %CHLIST_NEW )
{
  $CH_INSERT++;
  $DB_CHANGE=1;
  $CHANID_LAST++;
  ($chno_n,$tvpid_n,$icon_n,$name_n,$url_n) = @{$CH}{ ('chno','tvpid','icon','name','url') };
print "+ $url_n $name_n\n" if ($DEBUG);

  $dbh->do("INSERT INTO channel (chanid,channum,freqid,callsign,name,icon,xmltvid,sourceid) VALUES('$CHANID_LAST','$chno_n','$url_n','$chid','$name_n','$icon_n','$tvpid_n','$SOURCE_ID')");
}

# устанавливаем или сбрасываем флаг изменений
$dbh->do("UPDATE settings SET data='$DB_CHANGE' WHERE value='iptv_playlist_change'");


# отключаемся от БД
$dbh->disconnect();


print "Channel  update: $CH_UPDATE\n";
print "Channel  delete: $CH_DELETE\n";
print "Channel  insert: $CH_INSERT\n";
print "Set flag iptv_playlist_change=$DB_CHANGE\n";



#######################################################
# Функции
sub http_get
{
  my $url=shift;
  my ($host,$port,$url,$file)=parse_url($url);

  if ($host eq '') { return undef; }
  socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));

  my $iaddr = inet_aton($host);
  my $paddr = sockaddr_in($port, $iaddr);

  connect(SOCK, $paddr) || return undef;;
  send (SOCK, "GET /$url HTTP/1.0\nHOST:$host\n\n", 0) || return undef;;

  my @data=<SOCK>;

  close(SOCK);

  my $skip=1;
  my $str;
  my $content_type;
  my $buff;

  foreach $str (@data)
  {
    if ($skip)
    {
      if ($str=~/^[\r\n]$/)             { $skip=0; next; }
      if ($str=~/Content-Type: (.+)$/i) { $content_type=$1; }
      next;
    }
    $buff.=$str;
  }

  return ($content_type,$file,$buff);
}


# http://host[:port]/path/file[?args]
sub parse_url
{
  my $url=shift;
  my $host;
  my $port;
  my $file;

  if    ($url=~/^https\:\/\/(.*)$/) { $port=443; $url=$1; }
  elsif ($url=~/^http\:\/\/(.*)$/)  { $port=80;  $url=$1; }
  else  { return undef; }

  if    ($url=~/^([^\/]+)(\/.*)$/)  { $host=$1; $url=$2; }  else { return undef; }
  if    ($host=~/^(.+):(.+)$/)      { $host=$1; $port=$2; }
  if    ($url=~/\/([^\/]*)$/)       { $file=$1; if ($file=~/^(.+)\?/) { $file=$1; } }

  return ($host,$port,$url,$file);
}
