0

I want to show on a very simple way a TV guide timeline, but i'm really new into this, so I hope somebody can help me I on't want nothing too complicated, and I already search on the web and I find very complex timelines with a lot of functions that i really don't need, I just want to display the current and upcoming tv shows, but I don't know how to do it, something like this:

A really simple timetable

I don't need help to the php mysql connection, I already know how to do that, I just really need help with how display a table like this. This is how my sql table looks:

----------------------------------------------------------------
|  start   |   end    |  channel  |      title      |   info   |
----------------------------------------------------------------
| DATETIME | DATETIME |    INT    |      TEXT       |   TEXT   |
----------------------------------------------------------------

no matter if the table it's static, I really don't need an interactive timetable, just I need to display the current show and maybe the next 4 hour upcoming shows, I hope somebody can help me or give me the link of a open source or commercial script

ozonostudio
  • 119
  • 2
  • 6
  • 13
  • You want to a) scrape the data from a web site, b) store the data to a mySQL database, and c) display the database contents as a HTML page ... right? – hherger Jan 16 '16 at 21:52
  • @hherger Just display the database content as a simple table like the one on the picture – ozonostudio Jan 16 '16 at 23:43
  • If you are scraping - subject to a polite request to them for copyright acceptance - you could fill your boots with data for it here http://www.tvguide.co.uk/ and use `// For PHP 5 and up $handle = fopen("http://www.tvguide.co.uk/", "r"); $contents = stream_get_contents($handle); $contents_array = explode("hb-container",$contents);` would split most of the content into an array position e.g. `$contents_array[1];` Otherwise loop out your data with chunks of html concatenated with your data `while you have rows of data echo '' . $yourdata1 . '' . $yourdata2 . '';` – Steve Jan 17 '16 at 01:06
  • Or maybe just go for this pre built project http://forum.kodi.tv/showthread.php?tid=120377 with data from here http://wiki.xmltv.org/index.php/Main_Page – Steve Jan 17 '16 at 01:15
  • @Steve I already have my own database with all the scheduled hours I just want a way to display this as a table just like the image – ozonostudio Jan 17 '16 at 01:51
  • Hopefully the prebuilt project might do that - can you loop out your data from your query like in my comment? You could use divs and set their style widths inline according to the duration of each show. – Steve Jan 17 '16 at 02:02
  • Does this help? http://stackoverflow.com/questions/14430174/use-php-to-display-mysql-results-in-html-table and http://www.w3schools.com/php/php_mysql_select.asp – Steve Jan 17 '16 at 02:16
  • Seems that mysqli is now considered the best way to do database queries not mysql - the link from w3c is mysqli code. YourCommonSense's answer has something similar to what you need - you could replace `` etc with `
    ` where 100 is an arbitrary divisor - you could find a number that would give you appropriate results perhaps? Each station could be a row of divs so they could move independently, not like a table.
    – Steve Jan 17 '16 at 02:28
  • Ok let's do this again, I already know how create a table from mysql, the really think that is annoying me is the fact that I can't set the width of the cell according to the show length and all i can't adjust the top header with the hours. – ozonostudio Jan 17 '16 at 04:06
  • @ozonostudio: so, please tell us wheret the data comes from, andgiveus an example. – hherger Jan 17 '16 at 08:43
  • How accurate must be your timeline ? Do you want to display per minute ? If per hour is ok for you, you could loop through your results using `` where needed, `$x` being 2 , 3, 4 etc ... according to the length of the show : your cell will be 2, 3, 4 ... hours wide. – SunnyOne Jan 17 '16 at 09:22
  • @ozonostudio doesn't something like px"> do that? (assumed duration was in microtime or seconds) - assuming your duration is in minutes $duration x 4 would give you four hours width in a 960px wide page. – Steve Jan 17 '16 at 15:37
  • @SunnyOne Usually here on Mexico the show ends/start something like this: 01:05 - 12:35 - 23:15 - :10 - :20 - :45 - etc from 5 minutes to 5 minutes – ozonostudio Jan 17 '16 at 19:41

1 Answers1

1

So, here is a solution for your problem, I guess.
I suggest that you study the code, learn from it, and enhance it ;-). And, I'd be glad to get some feedback from you!

The database uses the same item names and item types as you describe in your question.

The script index.php has a configuration section at the top where you should modify the parameters as necessary.

These are the blocks of the script:

  • Connect to database
  • Initialise
  • Prepare header
  • Get data from database
  • Prepare content, format data
  • Read template and replace variables
  • Send generated output

The output is laid out as DIVs of variable widths corresponding to the different durations of the TV shows. The widths are calculated as percents, which makes the layout somehow responsive to different screen sizes.
An overlay DIV shows a marker for the current time.

As you can see, I use a template tvprogramme.tpl which contains variable references: variable names embraced in curly brackets like this {{varname}}. The script replaces these at the end by runtime values.

Embedded in the template you find the style definitions (CSS), plus a script which refreshes the page at configurable intervals. You could use an AJAX call to refresh parts of the page if required. And, of course, both the style and javascript definitions could alternatively be held in separate files.

I suggest to store both files (index.php, tvprogramme.tpl) UTF-8 formatted, without BOM. As you are probably living in the 7-bit world the solution might also work properly when the files are stored in ANSII format.

index.php (script)

<?php // ä

// Configuration BEGIN ---------------------------------------------------------

define('displayhours',4); // Hours to display
define('chnlwidth',12);   // Width of channel column, in percents
define('bodymargin',8);   // Margin of BODY, in pixels
define('refreshpage',0.5);  // Refresh page interval, in minutes
define('dbname', 'tv');
define('dbtableprefix', 'tv_');
define('dbtable', 'programmes');
define('dbtable1', 'channels');
define('dbuserid', 'tv_user');
define('dbpasswd', 'tv_password');
define('dbhost', 'localhost');
define('dbport', '3306');
define('dbsocket', '');
date_default_timezone_set('America/New_York');

// Configuration END -----------------------------------------------------------

define('LBRK','<br />');

// Connect to database
$mysqli = new mysqli(dbhost, dbuserid, dbpasswd, dbname, dbport, dbsocket);
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error.LBRK;
    exit(1);
}

// Initialise
$time = (isset($_GET['time'])) ? $_GET['time'] : time();
define('fldwidth', (97.4-chnlwidth) / displayhours);
define('secsperhour',3600);
$starthour = $time - ($time % secsperhour);
$endhour = $starthour + (displayhours * secsperhour);
$marker = ($time % secsperhour) / secsperhour;


// $outvars holds variables referred in template
$outvars = array(
    'header'  => '',
    'content' => '',
    'channelwidth' => chnlwidth . '%',
    'markerwidth' => (chnlwidth + fldwidth * $marker) . '%',
    'markerheight' => (1.2) . 'em',
    'bodymargin'  => bodymargin,
    'fieldwidth' => fldwidth . '%',
    'panelminwidth' => 150 * displayhours,
    'refreshpage' => refreshpage * 60000,
);

// Prepare header
$outvars['header'] .= PHP_EOL . '            <div class="hd_channel" style="min-width: '.chnlwidth.'%;">' . date('D, M j',$time) . '</div>' . PHP_EOL;
for($xi=0; $xi<displayhours; $xi++) {
    $outvars['header'] .= '            <div class="hd_field" style="min-width: '.fldwidth.'%;">' . date('g A',$time + ($xi * secsperhour)) . '</div>' . PHP_EOL;
}

// Get data from database
$starttime = date('Y-m-d H:i:s',$starthour);
$starttime1= date('Y-m-d H:i:s',floor(($starthour+60) / 60) * 60);
$endtime   = date('Y-m-d H:i:s',$endhour);
$query = 
    'SELECT p.id as p_id, c.id as c_id, channel, channel_name, start, end, title, info' .
    ' FROM ' .     dbtableprefix . dbtable . ' p, ' . dbtableprefix . dbtable1 . ' c'.
    ' WHERE ( (  (NOT start < \'' . $starttime . '\') AND ' .
              '(NOT start > \'' . $endtime . '\') ' .
           ') OR ' .
           '(  (NOT end < \'' .   $starttime1 . '\') AND ' . 
              '(NOT end > \'' .   $endtime . '\') ' .
           ') ) AND ( p.channel = c.id  )' .
    ' ORDER BY channel, start;';
$result = $mysqli->query($query);
if ($result!==false) {
    // Query was successful, so prepare output
    $entries = array();
    $prevend = false;
    while($row = $result->fetch_assoc()) {
        // For every tuple from the database do ...
        $row['start'] = strtotime($row['start']);
        $row['end'] = strtotime($row['end']);
        $sleft  = ($row['start'] - $starthour) / secsperhour;
        $start = ($row['start']<$starthour) ? $starthour : $row['start'];
        $end   = ($row['end']>$endhour) ? $endhour : $row['end'];
        $sdelta = floor($end - 30 - $start) / secsperhour;
        if (!isset($entries[$row['channel']])) {
            $entries[$row['channel']] = array('name' => $row['channel_name']);
        }
        if (($sdelta+$sleft) > displayhours) $sdelta = displayhours - $sleft;
        if (isset($entries[$row['channel']]['values'])) {
            $ix = count($entries[$row['channel']]['values'])-1;
            $delta = $row['start'] - $entries[$row['channel']]['values'][$ix]['end'];
        } else {
            $delta = 0;
        }
        if ($delta>0) $delta /= secsperhour;
        $pad = ($delta>0) ? fldwidth * floor($delta / secsperhour) : 0;
        $dopad = ( ($prevend===false) || ($row['start'] != $prevend) );
        $entries[$row['channel']]['values'][] = array(
            'start'  => $row['start'],
            'end'    => $row['end'],
            'pad'    => $dopad ? (($delta>0) ? fldwidth * $delta : fldwidth * $sleft) : 0,
            'pleft'  => fldwidth * $sleft,
            'pdeltah' => fldwidth * $sdelta,
            'title' => $row['title'],
            'info' => $row['info'],
        );
        $prevend = $row['end'];
    }
    $outvars['markerheight'] = (1.2 + count($entries) * 2.7) . 'em';

    foreach($entries as $id => $entry) {
        $outvars['content'] .= PHP_EOL;
        $outvars['content'] .= '            <div class="ct_channel">' . $entry['name'] . LBRK . '&nbsp;</div>' . PHP_EOL;
        $pleft = 0;
        $psum = 0;
        foreach($entry['values'] as $k => $xe) {
            if ($xe['pad']>0) {
                $outvars['content'] .= '            <div class="ct_pad" style="width:' . $xe['pad'] . '%; min-width:' . $xe['pad'] . '%;"></div>' . PHP_EOL;
                $pleft = $xe['pad'];
                $psum += $xe['pad'];
            }
            $outvars['content'] .= '            <div class="ct_field" title="' . date('D d, g:i a',$xe['start']) . ' - ' . date('D d, g:i a',$xe['end']) . PHP_EOL . $xe['info'] . '" style="width:' . $xe['pdeltah'] . '%; min-width:' . $xe['pdeltah'] . '%;">' . 
            $xe['title'] . LBRK .$xe['info'] . '</div>' . PHP_EOL;
            $psum += $xe['pdeltah'];
        }
        $pad = (99-chnlwidth) - $psum;
    }
    $result->free();

    // Read template and replace variables
    $template = file_get_contents(dirname(__FILE__).'/tvprogramme.tpl');
    $output = preg_replace_callback('/(\{\{(.*?)\}\})/si', 'compute_replacement', $template);

    // Done, send it out
    echo $output;

} else {

    // Query failed
    echo "Failed to read the database table '" . dbtableprefix . dbtable . "'" .LBRK;
    exit(1);
}

// Return template variable
function compute_replacement($groups) {
    global $outvars;
    return isset($outvars[$groups[2]]) ? $outvars[$groups[2]] : '['.$groups[2].']';
}

?>

tvprogramme.tpl (template)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 

<title>TV Programmes</title>

<style type="text/css">
    BODY { font-family: tahoma, arial, helvetica, sans-serif; font-size: 76%; margin:{{bodymargin}}px; }
    P { margin:0; padding:0; }
    .hd_channel, .ct_channel { width:{{channelwidth}}; background-color:#006699; color:white; clear:left; float:left; vertical-align:top; font-size:1.0em; }
    .hd_field, .ct_field, .ct_pad {  vertical-align:top; font-size:1.0em; float:left; }
    .hd_channel, .hd_field, .ct_channel { border-style:solid; border-color:white; border-width:0 0 1px 1px; padding: 0 0 0 2px; }
    .hd_field { width:{{fieldwidth}}; background-color:#006699; color:white; }
    .ct_field { background-color:#009966; color:white;height:2.6em; padding: 0 2px 0 2px; }  
    .ct_channel, .ct_field { text-overflow: ellipsis; overflow:hidden; }
    .ct_channel { height:2.6em; }
    .ct_channel, .ct_pad, .ct_field { }
    .ct_pad { background-color:transparent; color:black; height:2.6em; }
    .hd_field, .ct_field, .ct_pad { border-style:solid; border-color:white; border-width:0 0 1px 1px; }
    .header, .content { width:100%; min-width:{{panelminwidth}}px; }
    .marker { left:{{bodymargin}}px; top:{{bodymargin}}px; position:absolute; min-width:{{markerwidth}}; border-color:red; border-style:solid; border-width:0 1px 0 0; height:{{markerheight}}; background-color:transparent; color: transparent; z-index:900; }
</style>

<script type="text/javascript">
    function refreshPage() {
        window.location.replace(window.location.pathname);
    }
</script>

</head>

<body onload="setTimeout('refreshPage();',{{refreshpage}});">

<div class="page">
    <div class="panel">
        <div class="header">
{{header}}
        </div>
        <div class="content">
{{content}}
        </div>
        <div class="marker">&nbsp;
        </div>
    </div>
</div>

</body>
</html>

When run…

From this input

enter image description here

…this output is generated

enter image description here

hherger
  • 1,660
  • 1
  • 10
  • 13
  • this looks great, but of me looks all messy I really don't know why, looks: – ozonostudio Jan 18 '16 at 20:48
  • Also if you need it this are the screenshots of my database: ![database structure](http://files.ozn.st/z6prG2zM0si9k42/Captura%20de%20pantalla%202016-01-18%20a%20las%202.35.21%20p.m..png) ![database content](http://files.ozn.st/y6Bu632H7Wl3t30/Captura%20de%20pantalla%202016-01-18%20a%20las%202.35.48%20p.m..png) Also just a simple question, isn' more easy just pull the channel name from the database instead of create an array? But your example looks really cool – ozonostudio Jan 18 '16 at 20:56
  • the table is tv_guide – ozonostudio Jan 18 '16 at 20:57
  • According your docu there is no channel name, but a channel id in the database, which is an integer value. – hherger Jan 18 '16 at 21:00
  • this is how looks: http://files.ozn.st/2k4vHo33reqTAOM, yes, the number on the channel row is the channel number, not the channel name XD – ozonostudio Jan 18 '16 at 21:02
  • What is messy? I do not know what the database contains. The special characters might come from a differing file coding (UTF-8, ANSII) – hherger Jan 18 '16 at 21:08
  • when I say messy i mean the white spaces created by the ct_pad div, what's that div? I just saw the code a few minutes ago so I still don't have clear all the parts, but like I say before It's a really cool script it's just what I was looking for, well at least for a nooby like me looks very easy and clear – ozonostudio Jan 18 '16 at 21:11
  • The white spaces, (ct_pad) DIVs pad times where no show to expect according the database. The green DIVs are positionned on the time scale reflecting the start and end times - I assume correctly. – hherger Jan 18 '16 at 21:17
  • Btw., what does the table "channels" in your database contain? – hherger Jan 18 '16 at 21:27
  • Maybe it's something broken with that DIVs because creates a (ct_pat) DIV after every (ct_channel) without exception and If I comment the line that create the (ct_pad) everything looks fine, but you're right I have some missing shows this is how looks [with the ct_pad DIV](http://files.ozn.st/gcwAh44z95J83Ti) and this is how loos [without it](http://files.ozn.st/a1q8r2A93d541g3) and like you can see on the first row there's a very, very small show at the end, and is nothing bad about it, this happens because I have a missing show that day – ozonostudio Jan 18 '16 at 21:29
  • Ok, obviously the query should join the 2 tables. I'll update the code accordingly later. I believe that the pad DIVs do make sense. Otherwise the shows are not coorectly positionned on the time axis. Could you post an SQL export of the tv table? – hherger Jan 18 '16 at 21:40
  • Updated the script to join the "programmes" and "channels" tables and to remove the "$channels" array. – hherger Jan 18 '16 at 22:16
  • I guess a solution for the white spaces, can be take the end hour for the pre show and the start from the next right? but how can be done? – ozonostudio Jan 18 '16 at 22:37
  • I don't agree. If the shows follow one another immediately there should not be any white spaces. Else ?? Do you have real data which you could send (e.g. at tempbox@methodica.info)? – hherger Jan 18 '16 at 22:43
  • Be sure to have the parameter in "date_default_timezone_set('America/New_York')" set correctly! Where do you live? – hherger Jan 19 '16 at 07:04
  • I once again made a small change and updated the script code. – hherger Jan 19 '16 at 08:46
  • I'm from México I know that part change to `date_default_timezone_set('America/Mexico_City');` – ozonostudio Jan 19 '16 at 23:38