4 import rtv_config
, rtv_propertiesfile
, rtv_utils
, rtv_selection
5 from rtv_orderedpropertiesfile
import OrderedPropertiesFile
7 FILENAME_DATE_FORMAT
= "%Y-%m-%d"
8 HTML_TIME_FORMAT
= "%H:%M"
12 HOR_PIXELS_PER_MIN
= 6.0
13 VER_PIXELS_PER_CHAN
= 35
16 SCREEN_WIDTH_PIXELS
= rtv_utils
.MINS_IN_DAY
* HOR_PIXELS_PER_MIN
18 DAY_START
= datetime
.time( 6, 0 )
20 class TVGuideGenerator( object ):
22 def __init__( self
, config
):
24 self
.startTime
= datetime
.datetime
.today()
26 def timesHoursToMinsDiff( self
, laterTime
, earlierTime
):
27 if laterTime
.hour
> earlierTime
.hour
:
28 return 60 * (laterTime
.hour
- earlierTime
.hour
) + (laterTime
.minute
- earlierTime
.minute
)
29 elif laterTime
.hour
< earlierTime
.hour
:
30 return 60 * ( laterTime
.hour
+ 24 - earlierTime
.hour
) + (laterTime
.minute
- earlierTime
.minute
)
31 elif laterTime
.minute
>= earlierTime
.minute
:
32 return laterTime
.minute
- earlierTime
.minute
34 return rtv_utils
.MINS_IN_DAY
+ (laterTime
.minute
- earlierTime
.minute
)
38 def get_times( self
):
40 time_tmpl
= rtv_utils
.read_file_into_str( self
.config
.html_time_file
)
46 startMins
= self
.timesHoursToMinsDiff( tm
, DAY_START
)
49 x
= LEFT_OFFSET
+ startMins
*HOR_PIXELS_PER_MIN
50 width
= lengthMins
*HOR_PIXELS_PER_MIN
- HOR_GAP_PIXELS
52 repl
= time_tmpl
.replace( "$time", tm
.strftime( HTML_TIME_FORMAT
) ).replace(
53 "$left", str( x
) ).replace(
54 "$width", str( width
) )
58 tm
= tm
.replace( hour
=0 )
60 tm
= tm
.replace( hour
=tm
.hour
+1 )
66 self
.favs_and_sels
= rtv_selection
.read_favs_and_selections(
69 self
.channel_xmltv2tzap
= rtv_propertiesfile
.PropertiesFile()
70 self
.channel_xmltv2tzap
.load( self
.config
.channel_xmltv2tzap_file
73 self
.channels_order
= OrderedPropertiesFile()
74 self
.channels_order
.load( self
.config
.channels_order_file
)
76 rtv_utils
.ensure_dir_exists( self
.config
.tvguide_dir
)
78 # Hash date -> open file
80 self
.times
= self
.get_times()
83 self
.single_day_foot
= None
84 self
.single_day_head
= None
85 ( self
.single_day_head_tmpl
, self
.single_day_foot
) = rtv_utils
.read_file_into_str(
86 self
.config
.html_single_day_file
).split( "$programmes" )
88 self
.prog_small_normal
= rtv_utils
.read_file_into_str(
89 self
.config
.html_programme_small_normal_file
)
90 self
.prog_small_highlight
= rtv_utils
.read_file_into_str(
91 self
.config
.html_programme_small_highlight_file
)
92 self
.prog_small_remind
= rtv_utils
.read_file_into_str(
93 self
.config
.html_programme_small_remind_file
)
94 self
.prog_small_record
= rtv_utils
.read_file_into_str(
95 self
.config
.html_programme_small_record_file
)
97 self
.prog_full_normal
= rtv_utils
.read_file_into_str(
98 self
.config
.html_programme_full_normal_file
)
99 self
.prog_full_highlight
= rtv_utils
.read_file_into_str(
100 self
.config
.html_programme_full_highlight_file
)
101 self
.prog_full_remind
= rtv_utils
.read_file_into_str(
102 self
.config
.html_programme_full_remind_file
)
103 self
.prog_full_record
= rtv_utils
.read_file_into_str(
104 self
.config
.html_programme_full_record_file
)
107 rtv_utils
.parse_xmltv_files( self
.config
, self
.sax_callback
)
109 for dt
in self
.html_files
.keys():
110 fl
= self
.html_files
[dt
]
111 fl
.write( rtv_utils
.encode_text( self
.single_day_foot
) )
114 def timedeltaToMins( self
, timedelta
):
115 return ( ( timedelta
.days
* rtv_utils
.SECS_IN_DAY
) + timedelta
.seconds
) / 60
117 def get_file_for_date( self
, date
):
118 if date
not in self
.html_files
:
119 fn
= os
.path
.join( self
.config
.tvguide_dir
,
120 "tv-%s.html" % date
.strftime( FILENAME_DATE_FORMAT
) )
121 print "Creating file '%s'" % fn
123 self
.html_files
[date
] = fl
125 # We assume that by the time we get to any programmes, we have been given all the channels
126 if self
.single_day_head
== None:
127 self
.single_day_head
= self
.single_day_head_tmpl
.replace( "$height",
128 str( VER_PIXELS_PER_CHAN
- VER_GAP_PIXELS
) )
129 self
.single_day_head
= self
.single_day_head
.replace( "$times", self
.times
)
130 self
.single_day_head
= self
.single_day_head
.replace( "$channels", self
.channels
)
132 fl
.write( rtv_utils
.encode_text( self
.single_day_head
) )
134 fl
= self
.html_files
[date
]
139 def get_adjusted_date( self
, dt
):
141 startTimeTime
= dt
.time()
142 if startTimeTime
< DAY_START
:
143 adjStartDate
= rdt
+ datetime
.timedelta( - 1 )
148 def sax_callback( self
, pi
):
150 adjStartDate
= self
.get_adjusted_date( pi
.startTime
)
151 adjEndDate
= self
.get_adjusted_date( pi
.endTime
)
153 fl
= self
.get_file_for_date( adjStartDate
)
154 self
.add_prog_to_file( pi
, fl
, adjStartDate
)
156 if adjEndDate
!= adjStartDate
:
157 fl2
= self
.get_file_for_date( adjEndDate
)
158 self
.add_prog_to_file( pi
, fl2
, adjEndDate
)
162 def add_prog_to_file( self
, pi
, fl
, dt
):
164 dayStart
= datetime
.datetime
.combine( dt
, DAY_START
)
168 startMins
= self
.timedeltaToMins( pi
.startTime
- dayStart
)
169 lengthMins
= self
.timedeltaToMins( pi
.endTime
- pi
.startTime
)
170 tmfmt
= pi
.startTime
.time().strftime( HTML_TIME_FORMAT
)
172 if startMins
+ lengthMins
< 0:
173 print "Programme appearing too early?"
175 if startMins
> rtv_utils
.MINS_IN_DAY
:
176 print "Programme appearing too late?"
179 lengthMins
+= startMins
181 extra_style
+= "border-left-style: none"
183 if startMins
+ lengthMins
>= rtv_utils
.MINS_IN_DAY
:
184 lengthMins
= rtv_utils
.MINS_IN_DAY
- startMins
185 extra_style
+= "border-right-style: none"
187 if not self
.channels_order
.has_key( pi
.channel
):
188 self
.channels_order
.set_value( pi
.channel
, pi
.channel
)
189 channelNum
= self
.channels_order
.get_position( pi
.channel
)
191 x
= LEFT_OFFSET
+ startMins
*HOR_PIXELS_PER_MIN
193 y
= TOP_OFFSET
+ channelNum
*VER_PIXELS_PER_CHAN
195 width
= lengthMins
*HOR_PIXELS_PER_MIN
- HOR_GAP_PIXELS
199 for fav
in self
.favs_and_sels
:
200 if fav
.matches( pi
):
202 prog_small_html
= self
.prog_small_record
203 prog_full_html
= self
.prog_full_record
206 prog_small_html
= self
.prog_small_normal
207 prog_full_html
= self
.prog_full_normal
209 prog_small_html
= prog_small_html
.replace( "$top", "%d" % y
)
210 prog_small_html
= prog_small_html
.replace( "$left", "%d" % x
)
211 prog_small_html
= prog_small_html
.replace( "$width", "%d" % width
)
212 prog_small_html
= prog_small_html
.replace( "$time", tmfmt
)
213 prog_small_html
= prog_small_html
.replace( "$title", pi
.title
)
214 prog_small_html
= prog_small_html
.replace( "$style", extra_style
)
215 prog_small_html
= prog_small_html
.replace( "$id",
218 fl
.write( rtv_utils
.encode_text( prog_small_html
) )
220 prog_full_html
= prog_full_html
.replace( "$title", pi
.title
)
221 prog_full_html
= prog_full_html
.replace( "$time", tmfmt
)
222 prog_full_html
= prog_full_html
.replace( "$channel",
224 prog_full_html
= prog_full_html
.replace( "$desc",
227 full_fl
= file( os
.path
.join( self
.config
.tvguide_dir
,
228 "prog-%d.inc" % self
.cur_id
), "w" )
229 full_fl
.write( rtv_utils
.encode_text( prog_full_html
) )
234 def generate( config
):
235 generator
= TVGuideGenerator( config
)