#!/usr/bin/ruby -w
#
# xmltv2html.rb - A Ruby script to tranform the XMLTV output into HTML.
#
# Version : 0.5.5
# Author : Kurt V. Hindenburg
#
# Copyright (C) 2003, 2004, 2005 Kurt V. Hindenburg
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
=begin
= NAME
= SYNOPSIS
xmltv2html.rb [arg1 ... argN] < xmltv.xml > listing.html
xmltv2html.rb -h|--help|-v|--version
= DESCRIPTION
((*xmltv2html*)) is a script that transforms the output from xmltv into HTML.
The HTML output has the times horizontally and the shows vertically. The
shows' information is displayed via a DHTML popup window. Virtually every
aspect of the HTML output can be customized using a configuration
file and a CSS file.
= OPTIONS
: -c, --configfile=FILE
Configuration file to use.
: --noconfigfile
Do not use any configuration file.
: --urlprev=URL
URL for previous link.
: --urlnext=URL
URL for next link.
: -h or --help
Display usage information.
: -v or --version
Display version information.
= AUTHOR
Written by Kurt V. Hindenburg
= COPYRIGHT
Copyright (C) 2003-2005 Kurt V. Hindenburg
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.
= FILES
* popup.js - The show's information is displayed using this JavaScript DHTML popup window script.
* xmltv2html.css - An optional CSS file used in the HTML output.
* xmltv2htmlrc - An optional configuration file.
= SEE ALSO
* ((<"xmltv2html.rb home page - http://kurt.hindenburg.name/projects/xmltv2html"|URL:http://kurt.hindenburg.name/projects/xmltv2html>))
* ((<"xmltv home page - http://sourceforge.net/projects/xmltv"|URL:http://sourceforge.net/projects/xmltv>))
* ((<"REXML home page - http://www.germane-software.com/software/rexml"|URL:http://www.germane-software.com/software/rexml>))
= BUGS
* Please process the xmltv.xml file through tv_sort ((*before*)) using xmltv2html.rb
=end
require "optparse"
require "rexml/document"
require 'singleton'
require 'time'
XMLTV2HTML_VERSION="0.5.5"
XMLTV2HTML_DATE="Sep 17, 2005"
module Xmltv2Html
def die(*args)
$stderr.print args
exit(1)
end
def info(*args)
$stderr.print args
end
end
def die(*args)
$stderr.print args
exit(1)
end
def info(*args)
$stderr.print args, "\n"
end
class Config
attr_reader(:times_interval, :channels_interval, :time_format_12)
attr_reader(:use_config_file, :verbose, :output_links)
attr_reader(:date_format, :categories)
attr_reader(:use_favorites, :favorites)
attr_reader(:output_date_in_time, :css_filename)
attr_reader(:use_programme_popup, :programme_popup_method)
attr_reader(:popup_title_format, :popup_body_format)
attr_reader(:popup_title_background_color, :popup_title_color)
attr_reader(:popup_title_font_size, :popup_body_font_size)
attr_reader(:popup_body_background_color, :popup_body_color)
attr_reader(:popup_body_width)
attr_reader(:popup_title_font, :popup_body_font)
attr_reader(:time_divisor)
attr_accessor(:start_date, :stop_date)
attr_accessor(:days, :total_hours, :total_span)
attr_accessor(:url_next, :url_prev)
attr_accessor(:start_time, :stop_time)
attr_accessor(:output_favorites)
def initialize
@opts = {}
@keys = %w{ times_interval chanels_interval time_format_12 }
@favorites = Hash.new
@use_config_file = true
@config_file="xmltv2htmlrc"
@total_hours = 0
@total_span = 0
@time_divisor = 10; # Divide programmes' times in X minute slots
@url_prev = nil
@url_next = nil
setDefaults
handleOpts
readConfigFile if @config_file and @use_config_file
# Convert favorite_list to Hash for fast lookup.
@favorite_list.each { |f|
f.gsub!(/&/,'&')
@favorites[f] = true
}
@days = 1
end
def setDefaults
### BEGIN CONFIGURATION
#
# Will output info to STDERR
@verbose = true
# Number of channels to repeat times horizontally; 0 to disable
@times_interval = 4
# Number of hours to repeat channels vertically; 0 to disable
@channels_interval = 4
# true = 12 hour format; false = 24 hour format
@time_format_12 = true
# Use channel favorites?
@use_favorites = true
# List favorite channels below (seperate by a ',')
# The titles must be exact, not regular expressions.
@favorite_list = [
"CSI: Crime Scene Investigation",
"Law & Order: Special Victims Unit", "Angel", "Law & Order",
"The Shield", "Law & Order: Criminal Intent",
"Charmed", "The West Wing"
]
# Print out list of favorites beneath the listings?
@output_favorites = false
# Name of CSS file
@css_filename = 'xmltv2html.css'
# Categories - use specified CSS class for given category.
# You must give the exact category for this to match. Look
# at the xml data file for a list of categories.
# Put the corresponding CSS class in your .css file
# .sports-event
# {
# color: red;
# background-color: white;
# }
@categories = {
"Sports event" => "sports-event",
"News" => "news"
}
# If true, will display date on the hour cell
# (helpful for multiple days).
# Color, etc in CSS file
@output_date_in_time = true
# The format to display the date
# %m = month (01..12); %d = day (01..31); %b = Abbr month (Jan)
# %a = Abbr weekday (Sun)
# @date_format = '%m-%d'
# @date_format = '%b %m-%d'
@date_format = '%a %d'
# Should the programme's description 'popup' on mouseover?
# This will enlarge the output by the size of all the programme's
# descriptions.
@use_programme_popup = true
# What method to use for popup? DHTML or STATUSBAR
# Some browsers disable pages from changing the statusbar.
@programme_popup_method = "DHTML" # "STATUSBAR"
# Title is the top line of popup; body is the below part.
# Define the popup: %T = title, %S = sub-title
# %D = description, %R = rating
# %P = previously-shown; will display (R)
# Example: @popup_title_format = "%T"
# Example: @popup_body_format = "%D %R"
# DHTML: You can put *some* CSS/HTML stuff here as well...
# STATUSBAR: NO HTML
@popup_title_format = "%T"
@popup_body_format = "%S %P %D Rating: %R"
# Attributes for the DHTML popup
@popup_title_color = "#FFFFFF"
@popup_title_font = "" # "Utopia"
@popup_title_font_size = "2" # FONT SIZE=
@popup_title_background_color = "#000099"
@popup_body_color = "#000000"
@popup_body_font = "" # "Utopia"
@popup_body_font_size = "1" # FONT SIZE=
@popup_body_background_color = "#E8E8FF"
@popup_body_width = "200" # pixels
# xmltv and xmltv2html home page links
@output_links = true
@start_time = ""
@stop_time = ""
### END CONFIGURATION
end
def readConfigFile
f=File.expand_path(@config_file)
return if not File.exists?(f)
return if not File.stat(f).readable_real?
begin
eval File.new(f).read
$stderr.print "^ Reading configuration file #{f}\n" if @verbose
rescue
warn("\nAn error occurred while reading #{f}; please fix!\n")
exit
end
end
def handleOpts
ARGV.options do
|opts|
opts.banner = "Usage: #{File.basename($0)} < xmltv.xml > tv.html\n"
# separater
opts.on_tail
opts.on_tail("common options:")
opts.on("-c", "--configfile=FILE", String, "config file to use") {
|@config_file|}
opts.on("--noconfigfile","do NOT use any config file") {
@use_config_file = false}
opts.on("--starttime=YYYYMMDDHHMM", String, "Start time") { |@start_time|}
opts.on("--stoptime=YYYYMMDDHHMM", String, "Stop time") { |@stop_time|}
opts.on("--urlprev=URL", String, "URL for previous link") { |@url_prev|}
opts.on("--urlnext=URL", String, "URL for next link") { |@url_next|}
# no argument, shows at tail
opts.on_tail("-h", "--help", "show this message") {puts opts; exit}
opts.on_head("specific options:")
# no argument
opts.on_tail("-v", "--version", "show version") do
print "xmltv2html.rb v#{XMLTV2HTML_VERSION} (#{XMLTV2HTML_DATE})\n\n"
print "Copyright (C) 2003, 2004, 2005 Kurt V. Hindenburg\n"
print "This is free software; see the source for copying conditions. There is NO\n"
print " warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
print "\npublic@kurt.hindenburg.name\n"
exit
end
begin
opts.parse!
rescue
die "\n * Invalid parameters given!\n\n"
end
end
end
end
class Time
class << self
### Time.
# time string in format 'yyyymmddhhmmss (+/-xxxx)'
def parse_xmltv_time(str)
begin
Time.parse(str.split(' ')[0])
rescue ArgumentError
die "Unable to parse #{str}\n\n"
end
end
end
### object.
# TODO: cache $params.time_divisor
def round_to_interval
self - (self.min % $params.time_divisor) * 60
end
end
class ProgrammeTime
attr_reader(:fullStartTime, :fullStopTime)
def initialize(start, stop)
@fullStartTime = Time.parse_xmltv_time(start)
@fullStopTime = Time.parse_xmltv_time(stop)
#$stderr.print "#{@fullStartTime}; "
@fullStartTime = @fullStartTime.round_to_interval
#$stderr.print "after #{@fullStartTime} \n"
@fullStopTime = @fullStopTime.round_to_interval
@start_date = nil
@stop_date = nil
end
def returnParsedTime(t)
begin
pt = Time.parse(t)
rescue ArgumentError
die "Unable to parse #{t}\n\n"
end
pt
end
def calculateStartSlot
return if $params.start_date == nil # 1st pass
@start_date = returnParsedTime($params.start_date) if not @start_date
start_diff_min = ((@fullStartTime - @start_date) / 60).to_i
# $stderr.print ", diff #{start_diff_min}"
start_slot = start_diff_min / $params.time_divisor
# $stderr.print "starting slot #{start_slot}\n"
start_slot
end
def calculateStopSlot
return if $params.stop_date == nil # 1st pass
@start_date = returnParsedTime($params.start_date) if not @start_date
stop_diff_min = ((@fullStopTime - @start_date) / 60).to_i
stop_slot = stop_diff_min / $params.time_divisor
# $stderr.print " stoping slot #{stop_slot}\n"
# (@fullStopTime.hour * 60 / $timeDivisor) + (@fullStopTime.min / $timeDivisor)
stop_slot
end
end
class Programme
attr_reader :title, :subtitle, :span, :times, :desc, :rating, :category
attr_reader :previouslyShown, :spanSlots, :startSlot
attr_accessor :popupIndex
# attr_accessor :popupIndex
def initialize(title, subtitle, channel, start, stop, desc, rating, cats, rerun)
@title = title
@title.gsub!(/&/,'&')
@subtitle = subtitle
@channelid = channel
@desc = desc
@rating = rating
@category = cats
@previouslyShown = rerun
@popupIndex = -1
@times = ProgrammeTime.new(start, stop)
end
# Slot interval = 12 (60 minutes / 5 minutes)
def calculateSlots
@startSlot = @times.calculateStartSlot
@stopSlot = @times.calculateStopSlot
return if not @startSlot
return if not @stopSlot
@spanSlots = @stopSlot - @startSlot
end
# def start_time
# @times.start_time
# end
# def stop_time
# @times.stop_time
# end
def to_s
@title
end
end
# channel id => [show1, show2, ...]
class Programmes < Hash
def []=(id, programme)
#info "Adding #{programme} to #{id}"
case programme
when Programme
begin
if empty? or not has_key?(id)
super id, Array.new << programme
else
super id, (fetch(id) << programme)
end
end
when Array
begin
delete id
super id, programme
end
else
$stderr.print "^^^ Programmes []= Unknown class=#{programme.class}\n"
end
end
end
class Channel
attr_reader(:name, :id, :fullname)
attr_reader(:programmes)
attr_accessor(:totalSpan)
def initialize(id, fn)
@id = id
@fullname = fn
@number = ""
@name = @fullname
@totalSpan = 0 # 24 hours * 4 = 96
@programmes = Programmes.new
end
def <=>(o)
fullname.to_i <=> o.fullname.to_i
end
def <<(p)
# info "#{@id} : Adding #{p}\n"
@programmes[@id] = p
end
def number_of_programmes
@programmes[@id].size
end
def programme_at(i)
@programmes[@id][i]
end
# Verify that each show's STOP date is the next show's START date
# Should not be needed if tv_sort was used.
# TODO: remove this once we can verify tv_sort was used on input data
def verifyStopDate
# @programmeList.each_index { |si|
# s = @programmeList[si]
# next_show = @programmeList[si.succ]
# next if next_show == nil
# next if s.times.fullStopTime == next_show.times.fullStartTime
#
# die "\n * A programme's stop time does not match the next \n" +
# " * programme's start time. \n" +
# " * Use tv_sort from the xmltv distribution to correct!\n" +
# " * Exiting...\n\n" if !stop
# }
end
def calc_programme_slots
@programmes[@id].each { |p|
p.calculateSlots
}
end
def calculateSlots(slist)
tinterval = $params.channels_interval * 60 / $params.time_divisor
left = []
right = slist.dup
index = 0
total = 0
slist.each { |e|
cmd = e.slice(0..0).to_s
span = e.slice(1..-1).to_i
if total + span > tinterval
# $stderr.print "removing #{e} ::: "
prev = tinterval - total
# $stderr.print "adding prev #{prev}; "
nxt = total + span - tinterval
# $stderr.print "adding next #{nxt}\n"
# exit if nxt + prev != span
if cmd == "D" # Dummy data
left.push "D"+prev.to_s
left.push "D"+nxt.to_s
else
if cmd =="Q" # The removed was a Q
left.push "Q"+prev.to_s
else
left.push "P"+prev.to_s
end
left.push "Q"+nxt.to_s
end
right.shift
break
elsif total + span == tinterval
total = 0
left.push e
right.shift
else
left.push e
right.shift
total += span
end
index += 1
}
left = left.concat(right)
# left.each { |i| $stderr.print "#{i}*" }; $stderr.print "\n"
left
end
# Create a slot list to account for displaying channel info
# $params.channel_interval = # of hours to display channel info
# Handle empty programmes at start/end of channel.
def createSlotList
l = Array.new
span_counter = 0
times_counter = 1
sindex = 0
total = 0
if $params.channels_interval > 0
tinterval = $params.channels_interval * 60 / $params.time_divisor
else
tinterval = 9999
end
ci = tinterval
slist = Array.new
s = @programmes[@id].first # 1st programme for this channel
if s.startSlot() > 0 # Missing programme at start
dummy_span = s.startSlot() - span_counter
slist.push "D"+dummy_span.to_s
end
@programmes[@id].each { |s|
slist.push "P"+s.spanSlots.to_s
}
if $params.channels_interval > 0
sl = calculateSlots(slist)
while sl != slist
slist = sl.dup
sl = calculateSlots(sl)
end
end
slist.each { |entry|
span = entry.slice(1..-1).to_i
l.push entry
total += span
l.push("C0") if (total % tinterval) == 0 and $params.channels_interval > 0
}
slist = l.unshift("C0") # Add left-most channel
# Add left-most channel if not already there
# slist = l
# slist = l.unshift("C0") if l[0] != "C0"
# slist = l.unshift("C0") if l[0, 1] != "C0"
# $stderr.print slist[0, 3],"\n"
# $stderr.print l[0, 3],"\n"
dinterval = $params.total_hours * 60 / $params.time_divisor
if total < dinterval # Not enough programmes' data at end
slist.push("D"+(dinterval - total).to_s)
slist.push("C0") if dinterval % tinterval == 0
end
slist
end
end
# [channel id] -> Channel
class Channels < Hash
include Singleton
attr_accessor(:output_total_hours)
def initialize
@output_total_hours = 0 # Set to hours displayed
@output_start_hour = 0 # Start of hours displayed
@output_stop_hour = 0 # Stop hours displayed
end
def calc_programmes_slots
each { |id, c|
c.calc_programme_slots
}
end
end
class XmlTV
attr_reader :srcInfoName
attr_reader :genInfoName
attr_reader :HTML_title # Title of HTML page
attr_reader :top_title # Title of HTML page
attr_accessor(:firstShowStartDate, :lastShowStartDate, :lastShowStopDate)
def initialize
@firstShowStartDate = "99999999999999"
@lastShowStartDate = "0"
@lastShowStopDate = "0"
file = $stdin
@doc = REXML::Document.new file
@doc.elements.each("tv") { |e| # Should only be one
# The date here is the date/time that the user obtained the tv
# listings, NOT the date/time of the actual shows.
# @date = e.attributes["date"]
@srcInfoName = e.attributes["source-info-name"]
@genInfoName = e.attributes["generator-info-name"]
@HTML_title = ""
}
end
def setTitle(dates)
@top_title = ""
@HTML_title = ""
@top_title += @srcInfoName + " :: " if @srcInfoName
t1 = Time.parse(@firstShowStartDate)
t2 = Time.parse(@lastShowStopDate)
@time_first = t1.strftime("%a %b %d %I:%M %p")
@time_last = t2.strftime("%a %b %d %I:%M %p %Z")
if ( (t1.hour == 0) or (t1.hour > 19) ) and (t2.hour < 05)
t3 = t1 + (5 * 3600)
@top_title += t3.strftime("%A %b %d")
@HTML_title = @top_title
@top_title += " "
@top_title += ""
@top_title += @time_first + " - " + @time_last + ""
else
@top_title += @time_first + " - " + @time_last
@HTML_title = @top_title
end
end
def parseChannels
channels = Channels.instance
@doc.elements.each("tv/channel") { |element|
id = element.attributes["id"]
fn = ""
element.each_element { |e|
if e.name == "display-name" # Use 1st entry
fn = e.text()
break
end
}
channels[id] = Channel.new(id, fn)
}
end
def parseProgrammes
channels = Channels.instance
@doc.elements.each("tv/programme") { |element|
title=""
subtitle=""
desc=""
rating=""
cats = nil
rerun = false
ndesc = ""
start = element.attributes["start"]
stop = element.attributes["stop"]
die "\n * No stop attribute in this programme...\n" +
" * Use tv_sort from the xmltv distribution to correct!\n" +
" * Exiting...\n\n" if !stop
dstart = start[0..13]
dstop = stop[0..13]
ext = start[14..-1]
if not $params.start_time.empty?
# $stderr.print "Desired start : #{$params.start_time}\n"
nstart = $params.start_time.clone
nstart[10..11] = $params.time_divisor.to_s
# If programme ends before the desired start time...
# Adjust for the time_divisor (round_to_interval)
if dstop < nstart
# $stderr.print "Delete programme - Desired start : #{$params.start_time}, "
# $stderr.print "programme stop : #{dstop}\n"
# $stderr.print "Old start time = #{$params.start_time}, new=#{nstart}\n"
next
end
end
# If programme starts after the desired stop time...
if (not $params.stop_time.empty?) and (dstart >= $params.stop_time)
# $stderr.print "Delete programme - Desired stop : #{$params.stop_time}, "
# $stderr.print "programme start : #{dstart}\n"
next
end
# If programme starts before the desired start time, change start
if (not $params.start_time.empty?) and (dstart < $params.start_time)
# $stderr.print "Change Start - new start : #{$params.start_time}, "
# $stderr.print "old start: #{dstart}\n"
# ndesc = "(" + start[8..9] + ":" + start[10..11] + ") "
start = $params.start_time + ext
dstart = start[0..13]
end
# If programme ends after the desired stop time, change stop
if (not $params.stop_time.empty?) and (dstop > $params.stop_time)
stop = $params.stop_time + ext
dstop = stop[0..13]
end
@firstShowStartDate = dstart if @firstShowStartDate > dstart
@lastShowStartDate = dstart if @lastShowStartDate < dstart
@lastShowStopDate = dstop if @lastShowStopDate < dstop
channel = element.attributes["channel"]
element.each_element {|e|
title = e.text() if e.name == "title"
subtitle = e.text() if e.name == "sub-title"
desc=e.text() if e.name == "desc"
rerun=true if e.name == "previously-shown"
if e.name == "rating"
rv = e.elements[1]
rating = rv.text() if rv.name == "value"
end
# Check to see if user want to use special CSS class for category
# FIXME: What happens when more than 1 category is triggered?
if e.name == "category"
if $params.categories.has_key?(e.text())
# $stderr.print "found #{e.text()}, using #{$params.categories[e.text()]}\n"
cats = $params.categories[e.text()];
end
end
}
title.gsub!(/[\"\'\`]/,'') # Remove "'`
title = title.unpack("U*").pack("C*")
subtitle = "" if not subtitle
subtitle.gsub!(/[\"\'\`]/,'') # Remove "'`
desc = "" if not desc
desc.gsub!(/[\"\'\`]/,'') # Remove "'`
desc = desc.unpack("U*").pack("C*")
desc = ndesc + desc if ndesc
rating = "" if not rating
rating.gsub!(/[\"\'\`]/,'') # Remove "'`
#$stderr.print "title=#{title}, desc=#{desc}, rating=#{rating}\n"
p = Programme.new(
title, subtitle, channel, start, stop, desc, rating, cats, rerun)
# plist[channel] = p
channels[channel] << p
}
end
end
class XMLTV2HTML
attr_accessor(:dates)
def initialize
@xml = XmlTV.new
@out = Html.new
@dates = Array.new
end
def parseXML
@xml.parseChannels
@xml.parseProgrammes
$params.start_date = @xml.firstShowStartDate
$params.stop_date = @xml.lastShowStopDate
# $stderr.print "Starting listings at #{$params.start_date}\n"
# $stderr.print "Stopping listings at #{$params.stop_date}\n"
# Force start/stop time on hour
$params.start_date[10,4] = "0000"
if $params.stop_date[10,2] != "00"
hour = ($params.stop_date[8,2]).to_i + 1
if hour > 23
$stderr.print "yuck #{hour}\n"
end
$params.stop_date[8,2] = hour.to_s.rjust(2).sub(/\s/,'0')
end
$params.stop_date[10,4] = "0000"
# $stderr.print "Starting listings at #{$params.start_date}\n"
# $stderr.print "Stopping listings at #{$params.stop_date}\n"
pstart = Time.parse($params.start_date)
pstop = Time.parse($params.stop_date)
$params.total_hours = ((pstop - pstart) / 3600).to_i
channels = Channels.instance
channels.calc_programmes_slots
fdate = $params.start_date[0,8]
ldate = $params.stop_date[0,8]
@xml.setTitle(@dates)
end
def generatePopups
i = 0
@out.outputPopupHTMLBegin
channels = Channels.instance
channels.each { |id, c|
i = @out.outputPopupDescs(c, i)
}
@out.outputPopupHTMLEnd
end
def generateHTML
sindex =-1
times_counter = 1
favorites_list = []
@out.dates = @dates
@out.doctype
@out.header(@xml.HTML_title)
generatePopups if $params.use_programme_popup
@out.text_before_table(@xml.top_title)
@out.table_start
@out.table_times
channels = Channels.instance
sorted_channels = channels.sort { |a, b| a[1]<=>b[1] }
sorted_channels.each { |id, c|
@out.outputChannelBegin
slot_list = c.createSlotList
next unless slot_list
i = 0
pi = -1
slot_list.each { |entry|
cmd = entry.slice(0..0).to_s
span = entry.slice(1..-1).to_i
case cmd
when "D"
@out.outputDummyProgramme(span)
when "P" # Programme
sindex += 1
pi += 1
prog = c.programme_at(pi)
@out.outputProgramme(prog, sindex, span)
# @out.outputProgramme(c.programme_at(pi), sindex, span)
if $params.use_favorites and $params.output_favorites and $params.favorites.has_key?(prog.title)
#$stderr.print "found a fav #{prog.title}\n"
favorites_list << prog
end
when "Q" # Use previous Programme's info
@out.outputProgramme(c.programme_at(pi), sindex, span)
when "C"
@out.outputChannel(c)
else
$stderr.print "Unknown slot entry #{entry}\n" ; exit
end
i += 1
}
@out.outputChannelEnd
@out.table_times if times_counter % $params.times_interval == 0
times_counter += 1
}
@out.table_end
@out.output_favorites_list(favorites_list) if not favorites_list.empty?
@out.text_after_table
@out.footer
end
end
class Html
attr_accessor(:hours, :dates)
def initialize
@hours = 0 # hours displayed
end
def nl
print "\n"
end
def nb
print " "
end
def dots
print "../"
end
def doctype
print ''
nl
end
def header(title)
print ''; nl
print ''; nl
print ''; nl
print ''
print title if title
print ''; nl
print ''; nl
if $params.use_programme_popup
if $params.programme_popup_method == "DHTML"
print ''; nl
else
print ''; nl
end
end
print ''; nl; print ''; nl
end
def outputPopupHTMLBegin
print '
This is only text
'; nl
print ''; nl
nl
end
def outputPopupDescs(c, cindex)
# The descriptions go here...Text[#]=["title","text"]
c.programmes[c.id()].each { |s|
title = $params.popup_title_format.sub(/\%T/, s.title)
title.sub!(/\%R/, s.rating)
desc = $params.popup_body_format.gsub(/%T/, s.title)
desc.sub!(/\%S/, s.subtitle)
if (s.previouslyShown) # rerun
desc.sub!(/\%P/, "(R)")
else
desc.sub!(/\%P/, "")
end
desc.sub!(/%D/, s.desc)
desc.sub!(/%R/, s.rating)
if s.desc != "" or s.rating != ""
print 'Text[',cindex,']=["',title,'","',desc,'"]'; nl
s.popupIndex = cindex
cindex += 1
end
}
nl
cindex
end
def footer
print ''
nl
end
def text_before_table(text)
if text
print '
'
print text
print '
'; nl
end
if $params.url_prev
print '<<< Previous | '
end
if $params.url_next
print 'Next >>>'
end
end
def text_after_table
if $params.url_prev
print '<<< Previous | '
end
if $params.url_next
print 'Next >>>'
end
print ' '
outputInfo
outputLinks if $params.output_links
end
def table_start
print '
'; nl
end
def table_end
print '
'; nl
end
# Space for channel names
def output_channel_space
print '
'; nb; print '
'; nl
end
def outputDate
days = @hours/24
colspan = 96
colspan += 96 / $params.channels_interval if $params.channels_interval > 0
print '
'; nl
(0 .. days-1).each { |d|
print '
','date here','
'; nl
}
print '
'; nl
end
def table_times
intervals = 60 / $params.time_divisor
# $stderr.print "Starting time #{$params.start_date}\n"
# $stderr.print "Stoping time #{$params.stop_date}\n"
# Need hour to start.... we'll force it to be on an hour later
starting_day = $params.start_date[6,2].to_i
starting_hour = $params.start_date[8,2].to_i
# $stderr.print "Day to start: #{starting_day}\n"
# $stderr.print "Hour to start: #{starting_hour}\n"
# $stderr.print "Total hours: #{$params.total_hours}\n"
print '
';
}
cs += 1
output_channel_space if $params.channels_interval > 0 and cs % $params.channels_interval == 0
}
print '
'; nl
print '
'; nl
output_channel_space
days = @hours/24
cs = 0
cdate = Time.parse($params.start_date)
(starting_hour .. starting_hour + $params.total_hours - 1).each { |hi|
h = hi % 24
print '
';
if $params.output_date_in_time
nl; print '
'; nl
print '
';
end
if $params.time_format_12
if h < 12
out = "#{h} am"
else
out = (h - 12).to_s + " pm"
end
out.gsub!(/^0/, '12')
else
out = sprintf "%02d", h
end
print out
if $params.output_date_in_time
print '