DVB-Epg

 view release on metacpan or  search on metacpan

lib/DVB/Epg.pm  view on Meta::CPAN

List eit generator rules.

Return reference to an array of arrays of rules.

=cut

sub listEit {
    my $self = shift;
    my $dbh = $self->{dbh};

    return $dbh->selectall_arrayref( "SELECT * FROM eit ORDER BY pid, uid"); 
}

=head3 listPid( )

List all destination pid defined in eit generator rules.

Return array of pids.

=cut

sub listPid {
    my $self = shift;
    my $dbh = $self->{dbh};

    my $ref = $dbh->selectcol_arrayref( "SELECT DISTINCT pid FROM eit ORDER BY pid"); 
    return ( defined ($ref) ? @{$ref} : () );
}

=head3 deleteEit( $pid, $service_id, $original_network_id, $transport_stream_id)

Delete eit generator rule.
Parameters are optional.

Return number of deleted rules.

=cut

sub deleteEit {
    my $self = shift;
    my ( $pid, $service_id, $original_network_id, $transport_stream_id) = @_;
    my $dbh = $self->{dbh};

    return $dbh->do( "DELETE FROM eit WHERE 1"
          . ( defined $pid ? " AND pid=$pid" : "" )
          . ( defined $service_id ? " AND service_id=$service_id" : "" )
          . ( defined $original_network_id ? " AND original_network_id=$original_network_id" : "" )
          . ( defined $transport_stream_id ? " AND transport_stream_id=$transport_stream_id" : "" ) );
}

=head3 updateEit( $pid )

Use eit rules for updateing Eit sections of given $pid in database.

Return 1 on success.
Return 0 if sections are already uptodate.
Return undef on error;

=cut

sub updateEit {
    my $self = shift;
    my $pid = shift;
    my $dbh  = $self->{dbh};
    my $updated = 0;

    if ( !defined $pid) {
        return;
    }

    my $sel = $dbh->prepare("SELECT * FROM eit WHERE pid=$pid");

    $sel->execute();

    my $ret;
    my $rule;
    while ( $rule = $sel->fetchrow_hashref ) {

        # first calculate present/following
        $ret = $self->updateEitPresent($rule);
        if( ! defined $ret) {
            return;
        };
        $updated |= $ret;

        # and then calculate schedule
        if ( $rule->{maxsegments} > 0 ) {
            $ret = $self->updateEitSchedule($rule);
            if( ! defined $ret) {
                return;
            };
            $updated |= $ret;
        }
    }
    return $updated;
}

=head3 updateEitPresent( $rule, $forced)

Update eit sections for given $rule.
$rule is reference to hash containing keys:
pid, service_id, original_network_id, transport_stream_id, service_id, maxsegments, actual

Update sections only if there are changes in event table of schedule since last update or 
the $forced flag is set to 1.

Return undef if failed.
Return 0 if sections are already uptodate.
Return 1 after updating sections.

=cut

sub updateEitPresent {
    my $self = shift;
    my $rule = shift;
    my $forced = shift // 0;
    my $dbh  = $self->{dbh};

    # extend the $rule information
    $rule->{table_id} = $rule->{actual} == 1 ? 0x4e : 0x4f;

    my $present_following = new DVB::EventInformationTable($rule);

    # lookup version_number used at last generation of eit and timestamp
    my $select = $dbh->prepare( "SELECT version_number, strftime('%s',timestamp) FROM eit_version "
            ." WHERE pid=$rule->{pid} AND table_id=$rule->{table_id} AND service_id=$rule->{service_id}" );

    $select->execute();
    my ( $last_version_number, $last_update_timestamp ) = $select->fetchrow_array();

    if( $forced) {
        $last_update_timestamp = 0;
    }

    # if lookup wasn't succesfull we need to update the eit anyway
    if ( !defined $last_version_number ) {
        $last_update_timestamp = 0;
        $last_version_number   = 0;
    }


    # always use this time in queries
    my $current_time = time();

    # find last started event
    $select = $dbh->prepare( "SELECT event_id, strftime('%s',start) AS start, strftime('%s',stop) AS stop, "
                . " info, strftime('%s',timestamp) AS timestamp FROM event "
                . " WHERE uid=$rule->{uid} AND start <= datetime( $current_time,'unixepoch') ORDER BY start DESC LIMIT 1" );
    $select->execute();

    my $last_started_event = $select->fetchrow_hashref;

    # find following event
    $select = $dbh->prepare( "SELECT event_id, strftime('%s',start) AS start, strftime('%s',stop) AS stop, "
                . " info, strftime('%s',timestamp) AS timestamp FROM event "
                . " WHERE uid=$rule->{uid} AND start > datetime( $current_time,'unixepoch') ORDER BY start LIMIT 1" );
    $select->execute();

    my $following_event = $select->fetchrow_hashref;

    my $buildEit = 0;

    # check if we need an update
    # is the last started event still lasting
    if ( defined $last_started_event && $last_started_event->{stop} > $current_time ) {

        # was the start already published or is there a change in the event data
        if (
            $last_started_event->{start} > $last_update_timestamp
            ||    # present event started after last update of eit
            $last_started_event->{timestamp} > $last_update_timestamp
            ||    # present event was modified since last update of eit
            defined $following_event

lib/DVB/Epg.pm  view on Meta::CPAN

        if ( defined $last_started_event && $last_started_event->{stop} > $last_update_timestamp
            ||    # end of last started event was not pulished
            defined $following_event && $following_event->{timestamp} > $last_update_timestamp
          )       # followig event was modified
        {
            $buildEit = 1;
        }
    }

    return 0 if !$buildEit;

    my $pevent;

    # if there is a current event add it to table
    # or add an empty section
    if ( defined $last_started_event && $last_started_event->{stop} > $current_time ) {
        $pevent = _unfreezeEvent( $last_started_event );
        $pevent->{running_status} = 4;
    }
    $present_following->add2Section( 0, $pevent );

    # if there is a following event add it to table
    my $fevent;
    if ( defined $following_event ) {
        $fevent = _unfreezeEvent( $following_event );
        $fevent->{running_status} = ( $following_event->{start} - $current_time ) < 20 ? 2 : 1;
    }
    $present_following->add2Section( 1, $fevent );

    #
    # Add this to playout and update version
    ++$last_version_number;

    # Remove all section of this table
    return 
      if !$dbh->do( "DELETE FROM section WHERE pid=$rule->{pid} AND service_id=$rule->{service_id} AND table_id=$rule->{table_id}" );

    my $insert = $dbh->prepare( "INSERT INTO section VALUES ( $rule->{pid}, $rule->{table_id}, $rule->{service_id}, ?, ?)");
    return if !$insert;

    my $sections = $present_following->getSections($last_version_number);

    foreach my $section_number ( keys %$sections ) {
        $insert->bind_param( 1, $section_number );
        $insert->bind_param( 2, $sections->{$section_number}, SQL_BLOB );
        $insert->execute();
    }
    return $dbh->do( "INSERT OR REPLACE INTO eit_version VALUES ($rule->{pid}, $rule->{service_id}, "
            . "$rule->{table_id}, $last_version_number, datetime( $current_time,'unixepoch'))"
    );
}

=head3 updateEitSchedule( $rule)

Update eit playout packet for given $rule.
$rule is reference to hash containing keys:
pid, service_id, original_network_id, transport_stream_id, service_id, maxsegments, actual

=cut

sub updateEitSchedule {
    my $self = shift;
    my $rule = shift;
    my $dbh  = $self->{dbh};

    my $num_subtable = int( ( $rule->{maxsegments} - 1 ) / 32 );

    # always use this time in queries
    my $current_time = time();

    my $last_midnight = int( $current_time / ( 24 * 60 * 60 ) ) * 24 * 60 * 60;

    # iterate over all subtables
    my $subtable_count = 0;
    while ( $subtable_count <= $num_subtable ) {

        # extend the $rule information
        $rule->{table_id} =
          ( $rule->{actual} == 1 ? 0x50 : 0x60 ) + $subtable_count;

        my $schedule = new DVB::EventInformationTable($rule);

        # lookup version_number used at last generation of eit and timestamp
        my $select = $dbh->prepare(
            "SELECT version_number, strftime('%s',timestamp) FROM eit_version 
                WHERE pid=$rule->{pid} AND table_id=$rule->{table_id} AND service_id=$rule->{service_id}"
        );
        $select->execute();
        my ( $last_version_number, $last_update_timestamp ) =
          $select->fetchrow_array();

        # if lookup wasn't succesfull we need to update the eit anyway
        if ( !defined $last_version_number ) {
            $last_update_timestamp = 0;
            $last_version_number   = 0;
        }

        # first segment number in this subtable
        my $first_segment = $subtable_count * 32;

        # start of subtable interval
        my $subtable_start = $last_midnight + $first_segment * 3 * 60 * 60;

        # last segment in this subtable (actually it is the next of the last)
        my $last_segment =
            $rule->{maxsegments} >= $first_segment + 32
          ? $first_segment + 32
          : $rule->{maxsegments};

        # end of subtable interval and maxsegments
        my $subtable_stop = $last_midnight + $last_segment * 3 * 60 * 60;

        # find last modification time of events in this subtable
        $select = $dbh->prepare( "SELECT strftime('%s',timestamp) AS timestamp FROM event "
                . "WHERE uid=$rule->{uid} "
                . "AND start >= datetime( $subtable_start,'unixepoch') "
                . "AND start < datetime( $subtable_stop,'unixepoch') "
                . "ORDER BY timestamp DESC LIMIT 1" );
        $select->execute();
        my ($last_event_modification) = $select->fetchrow_array() || 0;



( run in 2.454 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )