#!/usr/bin/ruby -w # # xmltv2html.rb - A Ruby script to tranform the XMLTV output into HTML. # # Version : 0.5.4 # 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.4" XMLTV2HTML_DATE="Sep 10, 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) 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" ] # 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 > 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 @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 @out.outputProgramme(c.programme_at(pi), sindex, span) 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.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 ''; 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 ''; nl output_channel_space cs = 0 (starting_hour .. starting_hour + $params.total_hours - 1).each { |h| (0 .. intervals-1).each { |hh| print ''; printf "%02d", hh * $params.time_divisor; 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 ''; 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 ''; print cdate.strftime($params.date_format) print '
'; nl else print ''; end cs += 1 cdate += 3600 # Add 1 hour output_channel_space if $params.channels_interval > 0 and cs % $params.channels_interval == 0 } print ''; nl end def outputChannelBegin print ''; nl end def outputChannelEnd print ''; nl end def outputChannel(c) print ''; print c.fullname; print ''; nl end def outputDummyProgramme(span) print 'No Data' end def outputProgramme(s, index, slots) if slots > 0 print '' elsif s.category print s.category,'">' else print 'programme">' end # Styles : 12=right; 1=center; 2=left; 3=float if $params.use_programme_popup if s.popupIndex >= 0 if $params.programme_popup_method == "DHTML" print ''; nl else print ''; nl end print s.title ; print ''; nl else print s.title ; nl end else print s.title ; nl end print ''; nl end def outputInfo print '
' print '' nl print "Generated by xmltv2html.rb v#{XMLTV2HTML_VERSION} (#{XMLTV2HTML_DATE})" print " on #{Time.now}" nl print '' print '
' end def outputLinks nl # print 'Links: ' print 'xmltv' nl print 'xmltv2html' nl end end $params = Config.new xmltv2html = XMLTV2HTML.new time1 = Time.new xmltv2html.parseXML time2 = Time.new $stderr.print "^ Parsing XML took #{time2-time1} seconds.\n" if $params.verbose time3 = Time.new xmltv2html.generateHTML time4 = Time.new $stderr.print "^ Generating HTML took #{time4-time3} seconds.\n" if $params.verbose exit # vim:set ts=3 sw=3 expandtab: