1 |
dpavlin |
18 |
#!/usr/bin/perl |
2 |
|
|
|
3 |
|
|
use warnings; |
4 |
|
|
use strict; |
5 |
|
|
|
6 |
|
|
use XML::Simple; |
7 |
|
|
use Data::Dump qw(dump); |
8 |
dpavlin |
26 |
use DateTime; |
9 |
dpavlin |
18 |
|
10 |
dpavlin |
26 |
my $step = 1; # min |
11 |
|
|
|
12 |
dpavlin |
18 |
my $tv = XMLin( 'tv.xml', |
13 |
|
|
ContentKey => '-content', |
14 |
|
|
); |
15 |
|
|
|
16 |
|
|
warn dump $tv; |
17 |
|
|
|
18 |
|
|
print qq| |
19 |
dpavlin |
19 |
<html> |
20 |
|
|
<head> |
21 |
|
|
<meta charset=utf-8> |
22 |
dpavlin |
18 |
|
23 |
|
|
<style type="text/css"> |
24 |
|
|
|
25 |
dpavlin |
24 |
td { |
26 |
|
|
font-family:sans-serif; |
27 |
|
|
vertical-align: top; |
28 |
dpavlin |
25 |
background: #eee; |
29 |
dpavlin |
24 |
} |
30 |
|
|
|
31 |
dpavlin |
26 |
td.blank { |
32 |
|
|
background: #fff; |
33 |
|
|
} |
34 |
|
|
|
35 |
|
|
th.odd { |
36 |
dpavlin |
25 |
background: #eef; |
37 |
dpavlin |
18 |
} |
38 |
|
|
|
39 |
dpavlin |
25 |
th.even { |
40 |
|
|
background: #fcc; |
41 |
|
|
} |
42 |
|
|
|
43 |
dpavlin |
19 |
.hhmm { |
44 |
|
|
font-size: 50%; |
45 |
|
|
color: #888; |
46 |
|
|
float: right; |
47 |
|
|
} |
48 |
|
|
|
49 |
dpavlin |
26 |
span.date { |
50 |
|
|
color: #fff; |
51 |
|
|
font-size: 150%; |
52 |
|
|
} |
53 |
|
|
|
54 |
dpavlin |
18 |
</style> |
55 |
|
|
|
56 |
dpavlin |
19 |
</head> |
57 |
|
|
<body> |
58 |
|
|
|
59 |
dpavlin |
25 |
<table> |
60 |
dpavlin |
18 |
<tr><td></td> |
61 |
|
|
|; |
62 |
|
|
|
63 |
|
|
my @channels = keys %{ $tv->{channel} }; |
64 |
|
|
warn "# channels ",dump @channels; |
65 |
|
|
|
66 |
|
|
print qq|<th><img src="|, $_->{'icon'}->{'src'}, qq|"><br>|, $_->{'display-name'}->{'content'}, qq|</th>| foreach map { $tv->{channel}->{$_} } @channels; |
67 |
|
|
|
68 |
|
|
print qq| |
69 |
|
|
</tr> |
70 |
|
|
|; |
71 |
|
|
|
72 |
|
|
my $programs; |
73 |
|
|
|
74 |
dpavlin |
26 |
my $date; |
75 |
dpavlin |
18 |
|
76 |
dpavlin |
26 |
sub iso_to_dt { |
77 |
|
|
my ( $date, $timezone ) = split(/\s/,shift); |
78 |
|
|
DateTime->new( |
79 |
|
|
year => substr($date, 0, 4), |
80 |
|
|
month => substr($date, 4, 2), |
81 |
|
|
day => substr($date, 6, 2), |
82 |
|
|
hour => substr($date, 8, 2), |
83 |
|
|
minute => substr($date, 10, 2), |
84 |
|
|
second => substr($date, 12, 2), |
85 |
|
|
# timezone => $timezone, |
86 |
|
|
); |
87 |
|
|
} |
88 |
dpavlin |
18 |
|
89 |
dpavlin |
26 |
sub duration_min { |
90 |
|
|
my $dt = shift; |
91 |
|
|
return |
92 |
|
|
$dt->hours * 60 |
93 |
|
|
+ $dt->minutes |
94 |
|
|
# + $dt->seconds |
95 |
|
|
; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
|
sub dt_hhmm { |
99 |
|
|
sprintf( '%02d:%02d', $_[0]->hour, $_[0]->minute ); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
foreach my $p ( sort { $a->{start} cmp $b->{start} } @{ $tv->{programme} } ) { |
103 |
|
|
|
104 |
dpavlin |
18 |
warn "# p ",dump $p; |
105 |
dpavlin |
26 |
my $dt_start = iso_to_dt $p->{start}; |
106 |
|
|
my $dt_stop = iso_to_dt $p->{stop}; |
107 |
dpavlin |
18 |
|
108 |
dpavlin |
26 |
my $t_diff = $dt_stop - $dt_start; |
109 |
|
|
my $duration = duration_min( $dt_stop - $dt_start ); |
110 |
|
|
|
111 |
|
|
warn "# t $dt_start - $dt_stop [$duration]\n"; |
112 |
|
|
|
113 |
|
|
if ( ! $date ) { |
114 |
|
|
$date = $dt_start->clone; |
115 |
dpavlin |
18 |
} |
116 |
dpavlin |
26 |
|
117 |
|
|
push @{ $programs->{ $p->{channel} } }, [ $dt_start, $duration, $p ]; |
118 |
dpavlin |
18 |
} |
119 |
|
|
|
120 |
|
|
warn "# programs ", dump $programs; |
121 |
|
|
|
122 |
dpavlin |
26 |
warn "# date $date\n"; |
123 |
dpavlin |
18 |
|
124 |
dpavlin |
26 |
#$date->set_hour( 0 ); |
125 |
|
|
$date->set_minute( 0 ); |
126 |
|
|
$date->set_second( 0 ); |
127 |
dpavlin |
18 |
|
128 |
dpavlin |
26 |
print qq|<tr><th colspan=|, $#channels + 2, qq|>$date</th></tr>\n|; |
129 |
|
|
foreach my $c ( @channels ) { |
130 |
|
|
my $start = $programs->{$c}->[0]->[0] || die "no first $c in ", dump $programs->{$c}; |
131 |
|
|
my $duration = duration_min( $start - $date ); |
132 |
|
|
warn "# padding $c $start $duration\n"; |
133 |
|
|
unshift @{ $programs->{$c} }, [ $date, $duration ]; |
134 |
|
|
} |
135 |
dpavlin |
18 |
|
136 |
dpavlin |
26 |
my $more = 1; |
137 |
dpavlin |
18 |
|
138 |
dpavlin |
26 |
while ( $more ) { |
139 |
dpavlin |
20 |
|
140 |
dpavlin |
26 |
my @td; |
141 |
|
|
|
142 |
|
|
$more = 0; |
143 |
|
|
|
144 |
|
|
foreach my $c ( @channels ) { |
145 |
|
|
|
146 |
|
|
next unless defined $programs->{$c}->[0]; |
147 |
|
|
$more++ unless $more; |
148 |
|
|
|
149 |
|
|
my $first_start = $programs->{$c}->[0]->[0]; |
150 |
|
|
|
151 |
|
|
warn "# first_start $c $first_start $date\n"; |
152 |
|
|
|
153 |
|
|
if ( $first_start <= $date ) { |
154 |
|
|
|
155 |
|
|
my $p = shift @{ $programs->{$c} }; |
156 |
|
|
|
157 |
|
|
my $td_attr = 'rowspan=' . int( $p->[1] / $step ); |
158 |
|
|
|
159 |
|
|
my $hhmm = dt_hhmm $p->[0]; |
160 |
|
|
|
161 |
|
|
my $html = ''; |
162 |
|
|
if ( $p->[2] ) { |
163 |
|
|
$html .= join("\n" |
164 |
|
|
, qq|<span class="hhmm">$hhmm<br>$p->[1]</span>| |
165 |
dpavlin |
20 |
, $p->[2]->{title}->{content} |
166 |
|
|
, "<!-- $c -->" |
167 |
dpavlin |
26 |
); |
168 |
|
|
} else { |
169 |
|
|
$td_attr .= ' class=blank'; |
170 |
|
|
} |
171 |
dpavlin |
20 |
|
172 |
dpavlin |
26 |
push @td, qq|<td $td_attr>$html</td>|; |
173 |
dpavlin |
18 |
} |
174 |
dpavlin |
26 |
} |
175 |
dpavlin |
18 |
|
176 |
dpavlin |
25 |
|
177 |
dpavlin |
26 |
my $th = ''; |
178 |
|
|
if ( $date->minute == 0 ) { |
179 |
|
|
$th = $date->hour; |
180 |
|
|
$th = qq|<span class=date title="$date">| . $date->day . qq|</span><br>$th| if $th == 0; |
181 |
dpavlin |
25 |
|
182 |
dpavlin |
26 |
my $span = 60 / $step; |
183 |
|
|
my $class = $date->hour % 2 == 0 ? 'even' : 'odd'; |
184 |
|
|
$th = qq|<th rowspan=$span class=$class>$th</th>|; |
185 |
|
|
|
186 |
dpavlin |
18 |
} |
187 |
dpavlin |
26 |
|
188 |
|
|
print "<!-- $date -->\n"; |
189 |
|
|
print qq|<tr>$th|, join('', @td), qq|</tr>\n|; |
190 |
|
|
|
191 |
|
|
$date->add( minutes => $step ); |
192 |
|
|
|
193 |
dpavlin |
18 |
} |
194 |
|
|
|
195 |
|
|
print qq| |
196 |
|
|
</table> |
197 |
dpavlin |
19 |
|
198 |
|
|
</body> |
199 |
|
|
|
200 |
|
|
</html> |
201 |
dpavlin |
18 |
|; |