xmltv2html 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +99 -0
- data/ChangeLog +776 -0
- data/README +41 -0
- data/bin/xmltv2html.rb +1155 -0
- data/contrib/README +3 -0
- data/contrib/kvh/generate_html +68 -0
- data/contrib/kvh/tvlistings +15 -0
- data/contrib/kvh/tvlistings_index +82 -0
- data/contrib/kvh/update-tvlistings +136 -0
- data/popup.js +227 -0
- data/xmltv2html.css +75 -0
- data/xmltv2htmlrc +102 -0
- metadata +64 -0
data/bin/xmltv2html.rb
ADDED
@@ -0,0 +1,1155 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# xmltv2html.rb - A Ruby script to tranform the XMLTV output into HTML.
|
4
|
+
#
|
5
|
+
# Version : 0.5.3
|
6
|
+
# Author : Kurt V. Hindenburg <public@kurt.hindenburg.name>
|
7
|
+
#
|
8
|
+
# Copyright (C) 2003, 2004, 2005 Kurt V. Hindenburg
|
9
|
+
#
|
10
|
+
# This program is free software; you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU General Public License as published by
|
12
|
+
# the Free Software Foundation; either version 2 of the License, or
|
13
|
+
# (at your option) any later version.
|
14
|
+
#
|
15
|
+
# This program is distributed in the hope that it will be useful,
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
# GNU General Public License for more details.
|
19
|
+
#
|
20
|
+
# You should have received a copy of the GNU General Public License
|
21
|
+
# along with this program; if not, write to the Free Software
|
22
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
23
|
+
#
|
24
|
+
|
25
|
+
=begin
|
26
|
+
|
27
|
+
= NAME
|
28
|
+
= SYNOPSIS
|
29
|
+
xmltv2html.rb [arg1 ... argN] < xmltv.xml > listing.html
|
30
|
+
xmltv2html.rb -h|--help|-v|--version
|
31
|
+
= DESCRIPTION
|
32
|
+
((*xmltv2html*)) is a script that transforms the output from xmltv into HTML.
|
33
|
+
The HTML output has the times horizontally and the shows vertically. The
|
34
|
+
shows' information is displayed via a DHTML popup window. Virtually every
|
35
|
+
aspect of the HTML output can be customized using a configuration
|
36
|
+
file and a CSS file.
|
37
|
+
= OPTIONS
|
38
|
+
: -c, --configfile=FILE
|
39
|
+
Configuration file to use.
|
40
|
+
: --noconfigfile
|
41
|
+
Do not use any configuration file.
|
42
|
+
: --urlprev=URL
|
43
|
+
URL for previous link.
|
44
|
+
: --urlnext=URL
|
45
|
+
URL for next link.
|
46
|
+
: -h or --help
|
47
|
+
Display usage information.
|
48
|
+
: -v or --version
|
49
|
+
Display version information.
|
50
|
+
= AUTHOR
|
51
|
+
Written by Kurt V. Hindenburg <public@kurt.hindenburg.name>
|
52
|
+
= COPYRIGHT
|
53
|
+
Copyright (C) 2003-2005 Kurt V. Hindenburg
|
54
|
+
|
55
|
+
This is free software; see the source for copying conditions.
|
56
|
+
There is NO warranty; not even for MERCHANTABILITY or FITNESS
|
57
|
+
FOR A PARTICULAR PURPOSE.
|
58
|
+
= FILES
|
59
|
+
* popup.js - The show's information is displayed using this JavaScript DHTML popup window script.
|
60
|
+
* xmltv2html.css - An optional CSS file used in the HTML output.
|
61
|
+
* xmltv2htmlrc - An optional configuration file.
|
62
|
+
= SEE ALSO
|
63
|
+
* ((<"xmltv2html.rb home page - http://kurt.hindenburg.name/projects/xmltv2html"|URL:http://kurt.hindenburg.name/projects/xmltv2html>))
|
64
|
+
* ((<"xmltv home page - http://sourceforge.net/projects/xmltv"|URL:http://sourceforge.net/projects/xmltv>))
|
65
|
+
* ((<"REXML home page - http://www.germane-software.com/software/rexml"|URL:http://www.germane-software.com/software/rexml>))
|
66
|
+
= BUGS
|
67
|
+
* Please process the xmltv.xml file through tv_sort ((*before*)) using xmltv2html.rb
|
68
|
+
|
69
|
+
=end
|
70
|
+
|
71
|
+
require "optparse"
|
72
|
+
require "rexml/document"
|
73
|
+
require 'singleton'
|
74
|
+
require 'time'
|
75
|
+
|
76
|
+
XMLTV2HTML_VERSION="0.5.3"
|
77
|
+
XMLTV2HTML_DATE="Jun 20, 2005"
|
78
|
+
|
79
|
+
# die - print message to stderr and exit
|
80
|
+
def die(*args)
|
81
|
+
$stderr.print args
|
82
|
+
exit(1)
|
83
|
+
end
|
84
|
+
|
85
|
+
class Config
|
86
|
+
attr_reader(:times_interval, :channels_interval, :time_format_12)
|
87
|
+
attr_reader(:use_config_file, :verbose, :output_links)
|
88
|
+
attr_reader(:date_format, :categories)
|
89
|
+
attr_reader(:use_favorites, :favorites)
|
90
|
+
attr_reader(:output_date_in_time, :css_filename)
|
91
|
+
attr_reader(:use_programme_popup, :programme_popup_method)
|
92
|
+
attr_reader(:popup_title_format, :popup_body_format)
|
93
|
+
attr_reader(:popup_title_background_color, :popup_title_color)
|
94
|
+
attr_reader(:popup_title_font_size, :popup_body_font_size)
|
95
|
+
attr_reader(:popup_body_background_color, :popup_body_color)
|
96
|
+
attr_reader(:popup_body_width)
|
97
|
+
attr_reader(:popup_title_font, :popup_body_font)
|
98
|
+
attr_reader(:time_divisor)
|
99
|
+
attr_accessor(:start_date, :stop_date)
|
100
|
+
attr_accessor(:days, :total_hours, :total_span)
|
101
|
+
attr_accessor(:url_next, :url_prev)
|
102
|
+
|
103
|
+
def initialize
|
104
|
+
@opts = {}
|
105
|
+
@keys = %w{ times_interval chanels_interval time_format_12 }
|
106
|
+
@favorites = Hash.new
|
107
|
+
@use_config_file = true
|
108
|
+
@config_file="xmltv2htmlrc"
|
109
|
+
@total_hours = 0
|
110
|
+
@total_span = 0
|
111
|
+
@time_divisor = 10; # Divide programmes' times in X minute slots
|
112
|
+
@url_prev = nil
|
113
|
+
@url_next = nil
|
114
|
+
|
115
|
+
setDefaults
|
116
|
+
handleOpts
|
117
|
+
readConfigFile if @config_file and @use_config_file
|
118
|
+
|
119
|
+
# Convert favorite_list to Hash for fast lookup.
|
120
|
+
@favorite_list.each { |f|
|
121
|
+
f.gsub!(/&/,'&')
|
122
|
+
@favorites[f] = true
|
123
|
+
}
|
124
|
+
@days = 1
|
125
|
+
end
|
126
|
+
|
127
|
+
def setDefaults
|
128
|
+
### BEGIN CONFIGURATION
|
129
|
+
#
|
130
|
+
|
131
|
+
# Will output info to STDERR
|
132
|
+
@verbose = true
|
133
|
+
|
134
|
+
# Number of channels to repeat times horizontally; 0 to disable
|
135
|
+
@times_interval = 4
|
136
|
+
|
137
|
+
# Number of hours to repeat channels vertically; 0 to disable
|
138
|
+
@channels_interval = 4
|
139
|
+
|
140
|
+
# true = 12 hour format; false = 24 hour format
|
141
|
+
@time_format_12 = true
|
142
|
+
|
143
|
+
# Use channel favorites?
|
144
|
+
@use_favorites = true
|
145
|
+
|
146
|
+
# List favorite channels below (seperate by a ',')
|
147
|
+
# The titles must be exact, not regular expressions.
|
148
|
+
@favorite_list = [
|
149
|
+
"CSI: Crime Scene Investigation",
|
150
|
+
"Law & Order: Special Victims Unit", "Angel", "Law & Order",
|
151
|
+
"The Shield", "Law & Order: Criminal Intent",
|
152
|
+
"Charmed", "The West Wing"
|
153
|
+
]
|
154
|
+
|
155
|
+
# Name of CSS file
|
156
|
+
@css_filename = 'xmltv2html.css'
|
157
|
+
|
158
|
+
# Categories - use specified CSS class for given category.
|
159
|
+
# You must give the exact category for this to match. Look
|
160
|
+
# at the xml data file for a list of categories.
|
161
|
+
# Put the corresponding CSS class in your .css file
|
162
|
+
# .sports-event
|
163
|
+
# {
|
164
|
+
# color: red;
|
165
|
+
# background-color: white;
|
166
|
+
# }
|
167
|
+
@categories = {
|
168
|
+
"Sports event" => "sports-event",
|
169
|
+
"News" => "news"
|
170
|
+
}
|
171
|
+
|
172
|
+
# If true, will display date on the hour cell
|
173
|
+
# (helpful for multiple days).
|
174
|
+
# Color, etc in CSS file
|
175
|
+
@output_date_in_time = true
|
176
|
+
|
177
|
+
# The format to display the date
|
178
|
+
# %m = month (01..12); %d = day (01..31); %b = Abbr month (Jan)
|
179
|
+
# %a = Abbr weekday (Sun)
|
180
|
+
# @date_format = '%m-%d'
|
181
|
+
# @date_format = '%b %m-%d'
|
182
|
+
@date_format = '%a %d'
|
183
|
+
|
184
|
+
# Should the programme's description 'popup' on mouseover?
|
185
|
+
# This will enlarge the output by the size of all the programme's
|
186
|
+
# descriptions.
|
187
|
+
@use_programme_popup = true
|
188
|
+
|
189
|
+
# What method to use for popup? DHTML or STATUSBAR
|
190
|
+
# Some browsers disable pages from changing the statusbar.
|
191
|
+
@programme_popup_method = "DHTML" # "STATUSBAR"
|
192
|
+
|
193
|
+
# Title is the top line of popup; body is the below part.
|
194
|
+
# Define the popup: %T = title, %S = sub-title
|
195
|
+
# %D = description, %R = rating
|
196
|
+
# %P = previously-shown; will display (R)
|
197
|
+
# Example: @popup_title_format = "%T"
|
198
|
+
# Example: @popup_body_format = "%D<br />%R"
|
199
|
+
# DHTML: You can put *some* CSS/HTML stuff here as well...
|
200
|
+
# STATUSBAR: NO HTML
|
201
|
+
@popup_title_format = "%T"
|
202
|
+
@popup_body_format = "%S %P<br />%D<br />Rating: %R"
|
203
|
+
|
204
|
+
# Attributes for the DHTML popup
|
205
|
+
@popup_title_color = "#FFFFFF"
|
206
|
+
@popup_title_font = "" # "Utopia"
|
207
|
+
@popup_title_font_size = "2" # FONT SIZE=
|
208
|
+
@popup_title_background_color = "#000099"
|
209
|
+
@popup_body_color = "#000000"
|
210
|
+
@popup_body_font = "" # "Utopia"
|
211
|
+
@popup_body_font_size = "1" # FONT SIZE=
|
212
|
+
@popup_body_background_color = "#E8E8FF"
|
213
|
+
@popup_body_width = "200" # pixels
|
214
|
+
|
215
|
+
# xmltv and xmltv2html home page links
|
216
|
+
@output_links = true
|
217
|
+
|
218
|
+
### END CONFIGURATION
|
219
|
+
end
|
220
|
+
|
221
|
+
def readConfigFile
|
222
|
+
f=File.expand_path(@config_file)
|
223
|
+
return if not File.exists?(f)
|
224
|
+
return if not File.stat(f).readable_real?
|
225
|
+
begin
|
226
|
+
eval File.new(f).read
|
227
|
+
$stderr.print "^ Reading configuration file #{f}\n" if @verbose
|
228
|
+
rescue
|
229
|
+
warn("\nAn error occurred while reading #{f}; please fix!\n")
|
230
|
+
exit
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def handleOpts
|
235
|
+
|
236
|
+
ARGV.options do
|
237
|
+
|opts|
|
238
|
+
opts.banner = "Usage: #{File.basename($0)} < xmltv.xml > tv.html\n"
|
239
|
+
|
240
|
+
# separater
|
241
|
+
opts.on_tail
|
242
|
+
opts.on_tail("common options:")
|
243
|
+
|
244
|
+
opts.on("-c", "--configfile=FILE", String, "config file to use") {
|
245
|
+
|@config_file|}
|
246
|
+
opts.on("--noconfigfile","do NOT use any config file") {
|
247
|
+
@use_config_file = false}
|
248
|
+
|
249
|
+
opts.on("--urlprev=URL", String, "URL for previous link") { |@url_prev|}
|
250
|
+
opts.on("--urlnext=URL", String, "URL for next link") { |@url_next|}
|
251
|
+
|
252
|
+
# no argument, shows at tail
|
253
|
+
opts.on_tail("-h", "--help", "show this message") {puts opts; exit}
|
254
|
+
|
255
|
+
opts.on_head("specific options:")
|
256
|
+
|
257
|
+
# no argument
|
258
|
+
opts.on_tail("-v", "--version", "show version") do
|
259
|
+
print "xmltv2html.rb v#{XMLTV2HTML_VERSION} (#{XMLTV2HTML_DATE})\n\n"
|
260
|
+
print "Copyright (C) 2003, 2004, 2005 Kurt V. Hindenburg\n"
|
261
|
+
print "This is free software; see the source for copying conditions. There is NO\n"
|
262
|
+
print " warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
263
|
+
print "\npublic@kurt.hindenburg.name\n"
|
264
|
+
|
265
|
+
exit
|
266
|
+
end
|
267
|
+
begin
|
268
|
+
opts.parse!
|
269
|
+
rescue
|
270
|
+
die "\n * Invalid parameters given!\n\n"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class Time
|
277
|
+
|
278
|
+
class << self
|
279
|
+
### Time.<method>
|
280
|
+
|
281
|
+
# time string in format 'yyyymmddhhmmss (+/-xxxx)'
|
282
|
+
def parse_xmltv_time(str)
|
283
|
+
begin
|
284
|
+
Time.parse(str.split(' ')[0])
|
285
|
+
rescue ArgumentError
|
286
|
+
die "Unable to parse #{str}\n\n"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
### object.<method>
|
292
|
+
|
293
|
+
# TODO: cache $params.time_divisor
|
294
|
+
def round_to_interval
|
295
|
+
self - (self.min % $params.time_divisor) * 60
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|
300
|
+
class ProgrammeTime
|
301
|
+
attr_reader(:fullStartTime, :fullStopTime)
|
302
|
+
|
303
|
+
def initialize(start, stop)
|
304
|
+
@fullStartTime = Time.parse_xmltv_time(start)
|
305
|
+
@fullStopTime = Time.parse_xmltv_time(stop)
|
306
|
+
|
307
|
+
#$stderr.print "#{@fullStartTime}; "
|
308
|
+
@fullStartTime = @fullStartTime.round_to_interval
|
309
|
+
#$stderr.print "after #{@fullStartTime} \n"
|
310
|
+
@fullStopTime = @fullStopTime.round_to_interval
|
311
|
+
|
312
|
+
@start_date = nil
|
313
|
+
@stop_date = nil
|
314
|
+
end
|
315
|
+
|
316
|
+
def returnParsedTime(t)
|
317
|
+
begin
|
318
|
+
pt = Time.parse(t)
|
319
|
+
rescue ArgumentError
|
320
|
+
die "Unable to parse #{t}\n\n"
|
321
|
+
end
|
322
|
+
pt
|
323
|
+
end
|
324
|
+
|
325
|
+
def calculateStartSlot
|
326
|
+
return if $params.start_date == nil # 1st pass
|
327
|
+
@start_date = returnParsedTime($params.start_date) if not @start_date
|
328
|
+
|
329
|
+
start_diff_min = ((@fullStartTime - @start_date) / 60).to_i
|
330
|
+
# $stderr.print ", diff #{start_diff_min}"
|
331
|
+
start_slot = start_diff_min / $params.time_divisor
|
332
|
+
# $stderr.print "starting slot #{start_slot}\n"
|
333
|
+
start_slot
|
334
|
+
end
|
335
|
+
def calculateStopSlot
|
336
|
+
return if $params.stop_date == nil # 1st pass
|
337
|
+
|
338
|
+
@start_date = returnParsedTime($params.start_date) if not @start_date
|
339
|
+
stop_diff_min = ((@fullStopTime - @start_date) / 60).to_i
|
340
|
+
stop_slot = stop_diff_min / $params.time_divisor
|
341
|
+
# $stderr.print " stoping slot #{stop_slot}\n"
|
342
|
+
|
343
|
+
# (@fullStopTime.hour * 60 / $timeDivisor) + (@fullStopTime.min / $timeDivisor)
|
344
|
+
stop_slot
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
class Channel
|
350
|
+
attr_reader(:programmeList, :name, :id, :fullname)
|
351
|
+
attr_accessor(:totalSpan)
|
352
|
+
|
353
|
+
def initialize(id, fn)
|
354
|
+
@id = id
|
355
|
+
@fullname = fn
|
356
|
+
@number = ""
|
357
|
+
@name = @fullname
|
358
|
+
@totalSpan = 0 # 24 hours * 4 = 96
|
359
|
+
@programmeList = nil
|
360
|
+
end
|
361
|
+
|
362
|
+
def <=>(o)
|
363
|
+
fullname.to_i <=> o.fullname.to_i
|
364
|
+
end
|
365
|
+
|
366
|
+
def setProgrammes(l)
|
367
|
+
@programmeList = l
|
368
|
+
end
|
369
|
+
|
370
|
+
# Verify that each show's STOP date is the next show's START date
|
371
|
+
# Should not be needed if tv_sort was used.
|
372
|
+
# TODO: remove this once we can verify tv_sort was used on input data
|
373
|
+
def verifyStopDate
|
374
|
+
@programmeList.each_index { |si|
|
375
|
+
s = @programmeList[si]
|
376
|
+
next_show = @programmeList[si.succ]
|
377
|
+
next if next_show == nil
|
378
|
+
next if s.times.fullStopTime == next_show.times.fullStartTime
|
379
|
+
|
380
|
+
die "\n * A programme's stop time does not match the next \n" +
|
381
|
+
" * programme's start time. \n" +
|
382
|
+
" * Use tv_sort from the xmltv distribution to correct!\n" +
|
383
|
+
" * Exiting...\n\n" if !stop
|
384
|
+
}
|
385
|
+
end
|
386
|
+
|
387
|
+
def calculateSlots(slist)
|
388
|
+
tinterval = $params.channels_interval * 60 / $params.time_divisor
|
389
|
+
left = []
|
390
|
+
right = slist.dup
|
391
|
+
index = 0
|
392
|
+
total = 0
|
393
|
+
slist.each { |e|
|
394
|
+
cmd = e.slice(0..0).to_s
|
395
|
+
span = e.slice(1..-1).to_i
|
396
|
+
if total + span > tinterval
|
397
|
+
# $stderr.print "removing #{e} ::: "
|
398
|
+
prev = tinterval - total
|
399
|
+
# $stderr.print "adding prev #{prev}; "
|
400
|
+
nxt = total + span - tinterval
|
401
|
+
# $stderr.print "adding next #{nxt}\n"
|
402
|
+
# exit if nxt + prev != span
|
403
|
+
|
404
|
+
if cmd == "D" # Dummy data
|
405
|
+
left.push "D"+prev.to_s
|
406
|
+
left.push "D"+nxt.to_s
|
407
|
+
else
|
408
|
+
if cmd =="Q" # The removed was a Q
|
409
|
+
left.push "Q"+prev.to_s
|
410
|
+
else
|
411
|
+
left.push "P"+prev.to_s
|
412
|
+
end
|
413
|
+
left.push "Q"+nxt.to_s
|
414
|
+
end
|
415
|
+
right.shift
|
416
|
+
break
|
417
|
+
elsif total + span == tinterval
|
418
|
+
total = 0
|
419
|
+
left.push e
|
420
|
+
right.shift
|
421
|
+
else
|
422
|
+
left.push e
|
423
|
+
right.shift
|
424
|
+
total += span
|
425
|
+
end
|
426
|
+
index += 1
|
427
|
+
}
|
428
|
+
left = left.concat(right)
|
429
|
+
# left.each { |i| $stderr.print "#{i}*" }; $stderr.print "\n"
|
430
|
+
left
|
431
|
+
end
|
432
|
+
|
433
|
+
# Create a slot list to account for displaying channel info
|
434
|
+
# $params.channel_interval = # of hours to display channel info
|
435
|
+
# Handle empty programmes at start/end of channel.
|
436
|
+
def createSlotList
|
437
|
+
l = Array.new
|
438
|
+
span_counter = 0
|
439
|
+
times_counter = 1
|
440
|
+
sindex = 0
|
441
|
+
total = 0
|
442
|
+
if $params.channels_interval > 0
|
443
|
+
tinterval = $params.channels_interval * 60 / $params.time_divisor
|
444
|
+
else
|
445
|
+
tinterval = 9999
|
446
|
+
end
|
447
|
+
ci = tinterval
|
448
|
+
|
449
|
+
slist = Array.new
|
450
|
+
|
451
|
+
s = @programmeList[0]
|
452
|
+
if s.startSlot() > 0 # Missing programme at start
|
453
|
+
dummy_span = s.startSlot() - span_counter
|
454
|
+
slist.push "D"+dummy_span.to_s
|
455
|
+
end
|
456
|
+
|
457
|
+
@programmeList.each { |s|
|
458
|
+
slist.push "P"+s.spanSlots.to_s
|
459
|
+
}
|
460
|
+
|
461
|
+
if $params.channels_interval > 0
|
462
|
+
sl = calculateSlots(slist)
|
463
|
+
while sl != slist
|
464
|
+
slist = sl.dup
|
465
|
+
sl = calculateSlots(sl)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
slist.each { |entry|
|
470
|
+
span = entry.slice(1..-1).to_i
|
471
|
+
l.push entry
|
472
|
+
total += span
|
473
|
+
l.push("C0") if (total % tinterval) == 0 and $params.channels_interval > 0
|
474
|
+
}
|
475
|
+
|
476
|
+
slist = l.unshift("C0") # Add left-most channel
|
477
|
+
|
478
|
+
dinterval = $params.total_hours * 60 / $params.time_divisor
|
479
|
+
if total < dinterval # Not enough programmes' data at end
|
480
|
+
slist.push("D"+(dinterval - total).to_s)
|
481
|
+
slist.push("C0") if dinterval % tinterval == 0
|
482
|
+
end
|
483
|
+
|
484
|
+
slist
|
485
|
+
end
|
486
|
+
|
487
|
+
end
|
488
|
+
|
489
|
+
class Programme
|
490
|
+
attr_reader :title, :subtitle, :span, :times, :desc, :rating, :category
|
491
|
+
attr_reader :previouslyShown, :spanSlots, :startSlot
|
492
|
+
attr_accessor :popupIndex
|
493
|
+
|
494
|
+
def initialize(title, subtitle, channel, start, stop, desc, rating, cats, rerun)
|
495
|
+
@title = title
|
496
|
+
@title.gsub!(/&/,'&')
|
497
|
+
@subtitle = subtitle
|
498
|
+
@channelid = channel
|
499
|
+
@desc = desc
|
500
|
+
@rating = rating
|
501
|
+
@category = cats
|
502
|
+
@previouslyShown = rerun
|
503
|
+
@popupIndex = -1
|
504
|
+
|
505
|
+
@times = ProgrammeTime.new(start, stop)
|
506
|
+
end
|
507
|
+
|
508
|
+
# Slot interval = 12 (60 minutes / 5 minutes)
|
509
|
+
def calculateSlots
|
510
|
+
@startSlot = @times.calculateStartSlot
|
511
|
+
@stopSlot = @times.calculateStopSlot
|
512
|
+
|
513
|
+
return if not @startSlot
|
514
|
+
return if not @stopSlot
|
515
|
+
|
516
|
+
@spanSlots = @stopSlot - @startSlot
|
517
|
+
end
|
518
|
+
|
519
|
+
end
|
520
|
+
|
521
|
+
# [channel id] -> Channel
|
522
|
+
class Channels < Hash
|
523
|
+
include Singleton
|
524
|
+
|
525
|
+
attr_accessor(:output_total_hours)
|
526
|
+
|
527
|
+
def initialize
|
528
|
+
@output_total_hours = 0 # Set to hours displayed
|
529
|
+
@output_start_hour = 0 # Start of hours displayed
|
530
|
+
@output_stop_hour = 0 # Stop hours displayed
|
531
|
+
end
|
532
|
+
|
533
|
+
end
|
534
|
+
|
535
|
+
# channel id => [show1, show2, ...]
|
536
|
+
class Programmes < Hash
|
537
|
+
include Singleton
|
538
|
+
|
539
|
+
def []=(id, programme)
|
540
|
+
case programme
|
541
|
+
when Programme
|
542
|
+
begin
|
543
|
+
if empty? or not has_key?(id)
|
544
|
+
super id, Array.new << programme
|
545
|
+
else
|
546
|
+
super id, (fetch(id) << programme)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
when Array
|
550
|
+
begin
|
551
|
+
delete id
|
552
|
+
super id, programme
|
553
|
+
end
|
554
|
+
else
|
555
|
+
$stderr.print "^^^ Programmes []= Unknown class=#{programme.class}\n"
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
class XmlTV
|
562
|
+
attr_reader :srcInfoName
|
563
|
+
attr_reader :genInfoName
|
564
|
+
attr_reader :HTML_title # Title of HTML page
|
565
|
+
attr_reader :top_title # Title of HTML page
|
566
|
+
attr_accessor(:firstShowStartDate, :lastShowStartDate, :lastShowStopDate)
|
567
|
+
|
568
|
+
def initialize
|
569
|
+
@firstShowStartDate = "99999999999999"
|
570
|
+
@lastShowStartDate = "0"
|
571
|
+
@lastShowStopDate = "0"
|
572
|
+
|
573
|
+
file = $stdin
|
574
|
+
@doc = REXML::Document.new file
|
575
|
+
@doc.elements.each("tv") { |e| # Should only be one
|
576
|
+
# The date here is the date/time that the user obtained the tv
|
577
|
+
# listings, NOT the date/time of the actual shows.
|
578
|
+
# @date = e.attributes["date"]
|
579
|
+
@srcInfoName = e.attributes["source-info-name"]
|
580
|
+
@genInfoName = e.attributes["generator-info-name"]
|
581
|
+
@HTML_title = ""
|
582
|
+
}
|
583
|
+
end
|
584
|
+
|
585
|
+
def setTitle(dates)
|
586
|
+
@top_title = ""
|
587
|
+
@HTML_title = ""
|
588
|
+
@top_title += @srcInfoName + " :: " if @srcInfoName
|
589
|
+
t1 = Time.parse(@firstShowStartDate)
|
590
|
+
t2 = Time.parse(@lastShowStopDate)
|
591
|
+
|
592
|
+
@time_first = t1.strftime("%a %b %d %I:%M %p")
|
593
|
+
@time_last = t2.strftime("%a %b %d %I:%M %p %Z")
|
594
|
+
|
595
|
+
if (t1.hour > 19) and (t2.hour < 05)
|
596
|
+
t3 = t1 + (5 * 3600)
|
597
|
+
@top_title += t3.strftime("%A %b %d")
|
598
|
+
@HTML_title = @top_title
|
599
|
+
|
600
|
+
@top_title += "<br />"
|
601
|
+
@top_title += "<span style=\"font-size: smaller\">"
|
602
|
+
@top_title += @time_first + " - " + @time_last + "</span>"
|
603
|
+
else
|
604
|
+
@top_title += @time_first + " - " + @time_last
|
605
|
+
@HTML_title = @top_title
|
606
|
+
end
|
607
|
+
|
608
|
+
end
|
609
|
+
|
610
|
+
def parseChannels
|
611
|
+
channels = Channels.instance
|
612
|
+
@doc.elements.each("tv/channel") { |element|
|
613
|
+
id = element.attributes["id"]
|
614
|
+
fn = ""
|
615
|
+
element.each_element { |e|
|
616
|
+
if e.name == "display-name" # Use 1st entry
|
617
|
+
fn = e.text()
|
618
|
+
# $stderr.print "#{id}---#{fn}\n"
|
619
|
+
break
|
620
|
+
end
|
621
|
+
}
|
622
|
+
# $stderr.print "Using : #{id}---#{fn}\n"
|
623
|
+
channels[id] = Channel.new(id, fn)
|
624
|
+
}
|
625
|
+
end
|
626
|
+
|
627
|
+
def parseProgrammes
|
628
|
+
plist = Programmes.instance
|
629
|
+
|
630
|
+
@doc.elements.each("tv/programme") { |element|
|
631
|
+
title=""
|
632
|
+
subtitle=""
|
633
|
+
desc=""
|
634
|
+
rating=""
|
635
|
+
cats = nil
|
636
|
+
rerun = false
|
637
|
+
start = element.attributes["start"]
|
638
|
+
stop = element.attributes["stop"]
|
639
|
+
die "\n * No stop attribute in this programme...\n" +
|
640
|
+
" * Use tv_sort from the xmltv distribution to correct!\n" +
|
641
|
+
" * Exiting...\n\n" if !stop
|
642
|
+
|
643
|
+
dstart = start[0..13]
|
644
|
+
@firstShowStartDate = dstart if @firstShowStartDate > dstart
|
645
|
+
@lastShowStartDate = dstart if @lastShowStartDate < dstart
|
646
|
+
dstop = stop[0..13]
|
647
|
+
@lastShowStopDate = dstop if @lastShowStopDate < dstop
|
648
|
+
#$stderr.print "Start Date=#{dstart}, firstShowStartDate=#{firstShowStartDate}\n"
|
649
|
+
|
650
|
+
channel = element.attributes["channel"]
|
651
|
+
element.each_element {|e|
|
652
|
+
#$stderr.print e.text(),"\n"
|
653
|
+
title = e.text() if e.name == "title"
|
654
|
+
subtitle = e.text() if e.name == "sub-title"
|
655
|
+
desc=e.text() if e.name == "desc"
|
656
|
+
rerun=true if e.name == "previously-shown"
|
657
|
+
if e.name == "rating"
|
658
|
+
rv = e.elements[1]
|
659
|
+
rating = rv.text() if rv.name == "value"
|
660
|
+
end
|
661
|
+
|
662
|
+
# Check to see if user want to use special CSS class for category
|
663
|
+
# FIXME: What happens when more than 1 category is triggered?
|
664
|
+
if e.name == "category"
|
665
|
+
if $params.categories.has_key?(e.text())
|
666
|
+
# $stderr.print "found #{e.text()}, using #{$params.categories[e.text()]}\n"
|
667
|
+
cats = $params.categories[e.text()];
|
668
|
+
end
|
669
|
+
end
|
670
|
+
}
|
671
|
+
|
672
|
+
title.gsub!(/[\"\'\`]/,'') # Remove "'`
|
673
|
+
title = title.unpack("U*").pack("C*")
|
674
|
+
|
675
|
+
subtitle = "" if not subtitle
|
676
|
+
subtitle.gsub!(/[\"\'\`]/,'') # Remove "'`
|
677
|
+
|
678
|
+
desc = "" if not desc
|
679
|
+
desc.gsub!(/[\"\'\`]/,'') # Remove "'`
|
680
|
+
desc = desc.unpack("U*").pack("C*")
|
681
|
+
|
682
|
+
rating = "" if not rating
|
683
|
+
rating.gsub!(/[\"\'\`]/,'') # Remove "'`
|
684
|
+
#$stderr.print "title=#{title}, desc=#{desc}, rating=#{rating}\n"
|
685
|
+
|
686
|
+
plist[channel] = Programme.new(
|
687
|
+
title, subtitle, channel, start, stop, desc, rating, cats, rerun)
|
688
|
+
}
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
class XMLTV2HTML
|
693
|
+
attr_accessor(:dates)
|
694
|
+
|
695
|
+
def initialize
|
696
|
+
@xml = XmlTV.new
|
697
|
+
@out = Html.new
|
698
|
+
|
699
|
+
@dates = Array.new
|
700
|
+
end
|
701
|
+
|
702
|
+
def parseXML
|
703
|
+
|
704
|
+
@xml.parseChannels
|
705
|
+
@xml.parseProgrammes
|
706
|
+
|
707
|
+
$params.start_date = @xml.firstShowStartDate
|
708
|
+
$params.stop_date = @xml.lastShowStopDate
|
709
|
+
# $stderr.print "Starting listings at #{$params.start_date}\n"
|
710
|
+
# $stderr.print "Stopping listings at #{$params.stop_date}\n"
|
711
|
+
|
712
|
+
# Force start/stop time on hour
|
713
|
+
$params.start_date[10,4] = "0000"
|
714
|
+
|
715
|
+
if $params.stop_date[10,2] != "00"
|
716
|
+
hour = ($params.stop_date[8,2]).to_i + 1
|
717
|
+
if hour > 23
|
718
|
+
$stderr.print "yuck #{hour}\n"
|
719
|
+
end
|
720
|
+
$params.stop_date[8,2] = hour.to_s.rjust(2).sub(/\s/,'0')
|
721
|
+
end
|
722
|
+
$params.stop_date[10,4] = "0000"
|
723
|
+
# $stderr.print "Starting listings at #{$params.start_date}\n"
|
724
|
+
# $stderr.print "Stopping listings at #{$params.stop_date}\n"
|
725
|
+
|
726
|
+
pstart = Time.parse($params.start_date)
|
727
|
+
pstop = Time.parse($params.stop_date)
|
728
|
+
$params.total_hours = ((pstop - pstart) / 3600).to_i
|
729
|
+
|
730
|
+
# Traverse all channels' programmes and calculate their slots
|
731
|
+
# Delete any programme with span < 1
|
732
|
+
programmes = Programmes.instance
|
733
|
+
channels = Channels.instance
|
734
|
+
|
735
|
+
programmes.each { |id, programs|
|
736
|
+
total = 0
|
737
|
+
programs.each { |p|
|
738
|
+
p.calculateSlots
|
739
|
+
if p.spanSlots < 1
|
740
|
+
$stderr.print "Deleting #{p} span=#{p.spanSlots}\n"
|
741
|
+
delete p
|
742
|
+
else
|
743
|
+
total += p.spanSlots
|
744
|
+
end
|
745
|
+
}
|
746
|
+
# $stderr.print "Total span = #{total}\n"
|
747
|
+
channels[id].totalSpan = total
|
748
|
+
channels[id].setProgrammes programmes[id]
|
749
|
+
$params.total_span = total if total > $params.total_span
|
750
|
+
}
|
751
|
+
|
752
|
+
fdate = $params.start_date[0,8]
|
753
|
+
ldate = $params.stop_date[0,8]
|
754
|
+
|
755
|
+
@xml.setTitle(@dates)
|
756
|
+
|
757
|
+
end
|
758
|
+
|
759
|
+
def generatePopups
|
760
|
+
i = 0
|
761
|
+
@out.outputPopupHTMLBegin
|
762
|
+
|
763
|
+
channels = Channels.instance
|
764
|
+
channels.each { |id, c|
|
765
|
+
i = @out.outputPopupDescs(c, i)
|
766
|
+
}
|
767
|
+
@out.outputPopupHTMLEnd
|
768
|
+
end
|
769
|
+
|
770
|
+
def generateHTML
|
771
|
+
sindex =-1
|
772
|
+
times_counter = 1
|
773
|
+
|
774
|
+
@out.dates = @dates
|
775
|
+
|
776
|
+
@out.doctype
|
777
|
+
@out.header(@xml.HTML_title)
|
778
|
+
generatePopups if $params.use_programme_popup
|
779
|
+
@out.text_before_table(@xml.top_title)
|
780
|
+
@out.table_start
|
781
|
+
@out.table_times
|
782
|
+
|
783
|
+
channels = Channels.instance
|
784
|
+
sorted_channels = channels.sort { |a, b| a[1]<=>b[1] }
|
785
|
+
|
786
|
+
sorted_channels.each { |id, c|
|
787
|
+
@out.outputChannelBegin
|
788
|
+
slot_list = c.createSlotList
|
789
|
+
i = 0
|
790
|
+
pi = -1
|
791
|
+
slot_list.each { |entry|
|
792
|
+
cmd = entry.slice(0..0).to_s
|
793
|
+
span = entry.slice(1..-1).to_i
|
794
|
+
case cmd
|
795
|
+
when "D"
|
796
|
+
# $stderr.print "Dummy #{entry}\n"
|
797
|
+
@out.outputDummyProgramme(span)
|
798
|
+
when "P" # Programme
|
799
|
+
sindex += 1
|
800
|
+
pi += 1
|
801
|
+
# p = c.programmeList[pi]
|
802
|
+
# $stderr.print "#{entry} #{p}\n"
|
803
|
+
@out.outputProgramme(c.programmeList[pi], sindex, span)
|
804
|
+
when "Q" # Use previous Programme's info
|
805
|
+
p = c.programmeList[pi]
|
806
|
+
# $stderr.print "Programme- Use previous programme #{entry}\n"
|
807
|
+
# p = c.programmeList[pi-1]
|
808
|
+
@out.outputProgramme(c.programmeList[pi], sindex, span)
|
809
|
+
# @out.outputProgramme(p, sindex, span)
|
810
|
+
when "C"
|
811
|
+
# $stderr.print "Channel space #{cmd}\n"
|
812
|
+
@out.outputChannel(c)
|
813
|
+
else
|
814
|
+
$stderr.print "Unknown slot entry #{entry}\n" ; exit
|
815
|
+
$stderr.print "Using : #{id}---#{fn}\n"
|
816
|
+
end
|
817
|
+
i += 1
|
818
|
+
}
|
819
|
+
@out.outputChannelEnd
|
820
|
+
@out.table_times if times_counter % $params.times_interval == 0
|
821
|
+
times_counter += 1
|
822
|
+
}
|
823
|
+
|
824
|
+
@out.table_end
|
825
|
+
@out.text_after_table
|
826
|
+
@out.footer
|
827
|
+
end
|
828
|
+
|
829
|
+
end
|
830
|
+
|
831
|
+
class Html
|
832
|
+
attr_accessor(:hours, :dates)
|
833
|
+
|
834
|
+
def initialize
|
835
|
+
@hours = 0 # hours displayed
|
836
|
+
end
|
837
|
+
def nl
|
838
|
+
print "\n"
|
839
|
+
end
|
840
|
+
def nb
|
841
|
+
print " "
|
842
|
+
end
|
843
|
+
def dots
|
844
|
+
print "../"
|
845
|
+
end
|
846
|
+
def doctype
|
847
|
+
print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" >'
|
848
|
+
nl
|
849
|
+
end
|
850
|
+
def header(title)
|
851
|
+
print '<html><head>'; nl
|
852
|
+
print '<meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1">'; nl
|
853
|
+
print '<meta http-equiv="Content-language" content="en">'; nl
|
854
|
+
print '<title>'
|
855
|
+
print title if title
|
856
|
+
print '</title>'; nl
|
857
|
+
print '<link rel="stylesheet" href="', $params.css_filename
|
858
|
+
print '" type="text/css">'; nl
|
859
|
+
|
860
|
+
if $params.use_programme_popup
|
861
|
+
if $params.programme_popup_method == "DHTML"
|
862
|
+
print '<script language="JavaScript1.2" src="popup.js" type="text/javascript"></script>'; nl
|
863
|
+
else
|
864
|
+
print '<script language="JavaScript1.2" type="text/javascript">'
|
865
|
+
# April 02, 2004 : This doesn't work with Konqueor3.2.1
|
866
|
+
# nor firefox0.8
|
867
|
+
print 'window.defaultStatus = " "'
|
868
|
+
print '</script>'; nl
|
869
|
+
end
|
870
|
+
end
|
871
|
+
print '</head>'; nl; print '<body>'; nl
|
872
|
+
end
|
873
|
+
|
874
|
+
def outputPopupHTMLBegin
|
875
|
+
print '<div id="TipLayer" style="position: absolute; z-index: 1000; visibility: hidden; left: 0pt; top: -800px;"><table width="200" border="0" cellpadding="2" cellspacing="0" bgcolor="#000099"><tbody><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="0" bgcolor="#e8e8ff"><tbody><tr><td valign="top"><font size="1" face="Verdana,Arial,Helvetica" color="black">This is only text</font></td></tr></tbody></table></td></tr></tbody></table></div>'; nl
|
876
|
+
|
877
|
+
print '<script language="JavaScript1.2" type="text/javascript">'; nl
|
878
|
+
|
879
|
+
end
|
880
|
+
def outputPopupHTMLEnd
|
881
|
+
|
882
|
+
print 'var FiltersEnabled = 0 // if your not going to use transitions or filters in any of the tips set this to 0'; nl
|
883
|
+
|
884
|
+
# Styles
|
885
|
+
print 'Style[1]=['
|
886
|
+
print '"', $params.popup_title_color, '",'
|
887
|
+
print '"', $params.popup_body_color, '",'
|
888
|
+
print '"', $params.popup_title_background_color, '",'
|
889
|
+
print '"', $params.popup_body_background_color, '",'
|
890
|
+
print '"","","","",'
|
891
|
+
print '"', $params.popup_title_font, '",'
|
892
|
+
print '"', $params.popup_body_font, '",'
|
893
|
+
print '"center","",'
|
894
|
+
print '"', $params.popup_title_font_size, '",'
|
895
|
+
print '"', $params.popup_body_font_size, '",'
|
896
|
+
print $params.popup_body_width, ','
|
897
|
+
print '"",'
|
898
|
+
print '3,' # Border width
|
899
|
+
print '10,' # Padding around body text
|
900
|
+
print '20, 20, "", "", "", "", ""]'
|
901
|
+
print nl
|
902
|
+
|
903
|
+
print 'applyCssFilter()'; nl
|
904
|
+
print '</script>'; nl
|
905
|
+
nl
|
906
|
+
|
907
|
+
end
|
908
|
+
|
909
|
+
def outputPopupDescs(c, cindex)
|
910
|
+
# The descriptions go here...Text[#]=["title","text"]
|
911
|
+
id = c.id()
|
912
|
+
c.programmeList.each { |s|
|
913
|
+
title = $params.popup_title_format.sub(/\%T/, s.title)
|
914
|
+
title.sub!(/\%R/, s.rating)
|
915
|
+
desc = $params.popup_body_format.gsub(/%T/, s.title)
|
916
|
+
desc.sub!(/\%S/, s.subtitle)
|
917
|
+
if (s.previouslyShown) # rerun
|
918
|
+
desc.sub!(/\%P/, "(R)")
|
919
|
+
else
|
920
|
+
desc.sub!(/\%P/, "")
|
921
|
+
end
|
922
|
+
desc.sub!(/%D/, s.desc)
|
923
|
+
desc.sub!(/%R/, s.rating)
|
924
|
+
if s.desc != "" or s.rating != ""
|
925
|
+
print 'Text[',cindex,']=["',title,'","',desc,'"]'; nl
|
926
|
+
s.popupIndex = cindex
|
927
|
+
cindex += 1
|
928
|
+
end
|
929
|
+
}
|
930
|
+
nl
|
931
|
+
cindex
|
932
|
+
end
|
933
|
+
|
934
|
+
def footer
|
935
|
+
print '</body></html>'
|
936
|
+
nl
|
937
|
+
end
|
938
|
+
|
939
|
+
def text_before_table(text)
|
940
|
+
if text
|
941
|
+
print '<center><h3>'
|
942
|
+
print text
|
943
|
+
print '</h3></center>'; nl
|
944
|
+
end
|
945
|
+
if $params.url_prev
|
946
|
+
print '<a class="links" href="'
|
947
|
+
print $params.url_prev
|
948
|
+
print '"><<< Previous</a> | '
|
949
|
+
end
|
950
|
+
if $params.url_next
|
951
|
+
print '<a class="links" href="'
|
952
|
+
print $params.url_next
|
953
|
+
print '">Next >>></a>'
|
954
|
+
end
|
955
|
+
end
|
956
|
+
|
957
|
+
def text_after_table
|
958
|
+
if $params.url_prev
|
959
|
+
print '<a class="links" href="'
|
960
|
+
print $params.url_prev
|
961
|
+
print '"><<< Previous</a> | '
|
962
|
+
end
|
963
|
+
if $params.url_next
|
964
|
+
print '<a class="links" href="'
|
965
|
+
print $params.url_next
|
966
|
+
print '">Next >>></a>'
|
967
|
+
end
|
968
|
+
print '<br />'
|
969
|
+
outputInfo
|
970
|
+
outputLinks if $params.output_links
|
971
|
+
end
|
972
|
+
|
973
|
+
def table_start
|
974
|
+
print '<table width="100%" border="3" cellpadding="3">'; nl
|
975
|
+
end
|
976
|
+
def table_end
|
977
|
+
print '</table>'; nl
|
978
|
+
end
|
979
|
+
|
980
|
+
# Space for channel names
|
981
|
+
def output_channel_space
|
982
|
+
print '<td>'; nb; print '</td>'; nl
|
983
|
+
end
|
984
|
+
|
985
|
+
def outputDate
|
986
|
+
days = @hours/24
|
987
|
+
colspan = 96
|
988
|
+
colspan += 96 / $params.channels_interval if $params.channels_interval > 0
|
989
|
+
|
990
|
+
print '<tr class="date">'; nl
|
991
|
+
(0 .. days-1).each { |d|
|
992
|
+
print '<td colspan="',colspan,'" align="center">','date here','</td>'; nl
|
993
|
+
}
|
994
|
+
print '</tr>'; nl
|
995
|
+
end
|
996
|
+
|
997
|
+
def table_times
|
998
|
+
intervals = 60 / $params.time_divisor
|
999
|
+
|
1000
|
+
# $stderr.print "Starting time #{$params.start_date}\n"
|
1001
|
+
# $stderr.print "Stoping time #{$params.stop_date}\n"
|
1002
|
+
|
1003
|
+
# Need hour to start.... we'll force it to be on an hour later
|
1004
|
+
starting_day = $params.start_date[6,2].to_i
|
1005
|
+
starting_hour = $params.start_date[8,2].to_i
|
1006
|
+
# $stderr.print "Day to start: #{starting_day}\n"
|
1007
|
+
# $stderr.print "Hour to start: #{starting_hour}\n"
|
1008
|
+
# $stderr.print "Total hours: #{$params.total_hours}\n"
|
1009
|
+
|
1010
|
+
print '<tr class="time">'; nl
|
1011
|
+
output_channel_space
|
1012
|
+
|
1013
|
+
cs = 0
|
1014
|
+
(starting_hour .. starting_hour + $params.total_hours - 1).each { |h|
|
1015
|
+
(0 .. intervals-1).each { |hh|
|
1016
|
+
print '<td>';
|
1017
|
+
printf "%02d", hh * $params.time_divisor; print '</td>';
|
1018
|
+
}
|
1019
|
+
cs += 1
|
1020
|
+
output_channel_space if $params.channels_interval > 0 and cs % $params.channels_interval == 0
|
1021
|
+
}
|
1022
|
+
print '</tr>'; nl
|
1023
|
+
|
1024
|
+
print '<tr class="time">'; nl
|
1025
|
+
output_channel_space
|
1026
|
+
days = @hours/24
|
1027
|
+
cs = 0
|
1028
|
+
cdate = Time.parse($params.start_date)
|
1029
|
+
|
1030
|
+
(starting_hour .. starting_hour + $params.total_hours - 1).each { |hi|
|
1031
|
+
h = hi % 24
|
1032
|
+
print '<td colspan="',intervals,'" class="time">';
|
1033
|
+
|
1034
|
+
if $params.output_date_in_time
|
1035
|
+
nl; print '<table width="100%" border="0" cellpadding="0">'; nl
|
1036
|
+
print '<tr><td align="left" class="time">';
|
1037
|
+
end
|
1038
|
+
if $params.time_format_12
|
1039
|
+
if h < 12
|
1040
|
+
out = "#{h} am"
|
1041
|
+
else
|
1042
|
+
out = (h - 12).to_s + " pm"
|
1043
|
+
end
|
1044
|
+
out.gsub!(/^0/, '12')
|
1045
|
+
else
|
1046
|
+
out = sprintf "%02d", h
|
1047
|
+
end
|
1048
|
+
print out
|
1049
|
+
if $params.output_date_in_time
|
1050
|
+
print '<td align="right" class="date_in_time">';
|
1051
|
+
print cdate.strftime($params.date_format)
|
1052
|
+
print '</td></tr>'; nl; print '</table></td>'; nl
|
1053
|
+
else
|
1054
|
+
print '</td>';
|
1055
|
+
end
|
1056
|
+
cs += 1
|
1057
|
+
cdate += 3600 # Add 1 hour
|
1058
|
+
output_channel_space if $params.channels_interval > 0 and cs % $params.channels_interval == 0
|
1059
|
+
}
|
1060
|
+
print '</tr>'; nl
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
def outputChannelBegin
|
1064
|
+
print '<tr class="channel">'; nl
|
1065
|
+
end
|
1066
|
+
def outputChannelEnd
|
1067
|
+
print '</tr>'; nl
|
1068
|
+
end
|
1069
|
+
def outputChannel(c)
|
1070
|
+
print '<td class="channel">';
|
1071
|
+
print c.fullname; print '</td>'; nl
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def outputDummyProgramme(span)
|
1075
|
+
print '<td colspan="',span,'" class="dummy">No Data</td>'
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def outputProgramme(s, index, slots)
|
1079
|
+
if slots > 0
|
1080
|
+
print '<td colspan="', slots, '" class="'
|
1081
|
+
else
|
1082
|
+
print '<td colspan="',s.spanSlots,'" class="'
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
# Favorites override category.
|
1086
|
+
if $params.use_favorites and $params.favorites.has_key?(s.title)
|
1087
|
+
print 'favorite">'
|
1088
|
+
elsif s.category
|
1089
|
+
print s.category,'">'
|
1090
|
+
else
|
1091
|
+
print 'programme">'
|
1092
|
+
end
|
1093
|
+
# Styles : 12=right; 1=center; 2=left; 3=float
|
1094
|
+
if $params.use_programme_popup
|
1095
|
+
if s.popupIndex >= 0
|
1096
|
+
if $params.programme_popup_method == "DHTML"
|
1097
|
+
print '<a onmouseover="stm(Text[', s.popupIndex
|
1098
|
+
print '],Style[1])" onmouseout="htm()">'; nl
|
1099
|
+
else
|
1100
|
+
print '<a language="Javascript" '
|
1101
|
+
print 'onmouseover="window.status=Text[', s.popupIndex
|
1102
|
+
print '];return true"'
|
1103
|
+
# print ' OnMouseout="window.status=\' \';"'
|
1104
|
+
print '>'; nl
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
print s.title ; print '</a>'; nl
|
1108
|
+
else
|
1109
|
+
print s.title ; nl
|
1110
|
+
end
|
1111
|
+
else
|
1112
|
+
print s.title ; nl
|
1113
|
+
end
|
1114
|
+
print '</td>'; nl
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
def outputInfo
|
1118
|
+
print '<br>'
|
1119
|
+
print '<span class="info">'
|
1120
|
+
nl
|
1121
|
+
print "Generated by xmltv2html.rb v#{XMLTV2HTML_VERSION} (#{XMLTV2HTML_DATE})"
|
1122
|
+
print " on #{Time.now}"
|
1123
|
+
nl
|
1124
|
+
print '</span>'
|
1125
|
+
print '<br>'
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
def outputLinks
|
1129
|
+
nl
|
1130
|
+
# print 'Links: '
|
1131
|
+
print '<a class="links" href="http://sourceforge.net/projects/xmltv">xmltv</a>'
|
1132
|
+
nl
|
1133
|
+
print '<a class="links" href="http://kurt.hindenburg.name">xmltv2html</a>'
|
1134
|
+
nl
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
$params = Config.new
|
1140
|
+
xmltv2html = XMLTV2HTML.new
|
1141
|
+
|
1142
|
+
time1 = Time.new
|
1143
|
+
xmltv2html.parseXML
|
1144
|
+
time2 = Time.new
|
1145
|
+
$stderr.print "^ Parsing XML took #{time2-time1} seconds.\n" if $params.verbose
|
1146
|
+
|
1147
|
+
time3 = Time.new
|
1148
|
+
xmltv2html.generateHTML
|
1149
|
+
time4 = Time.new
|
1150
|
+
$stderr.print "^ Generating HTML took #{time4-time3} seconds.\n" if $params.verbose
|
1151
|
+
|
1152
|
+
exit
|
1153
|
+
|
1154
|
+
|
1155
|
+
# vim:set ts=3 sw=3 expandtab:
|