Descriptions now include cast and director
[xmltvtotgd.git] / icetotgd.py
blob78a786c6c8df3c489a96ea7dbba029d2efd66e01
1 #!/usr/bin/env python
2 from xml.etree import ElementTree as ET
3 import datetime
5 class IceToTgd(object):
7 def use_xml_file(self, filename):
8 self.tree = ET.parse(filename)
9 self.load_channels()
10 self.load_programmes()
12 def load_channels(self):
13 self.channels = dict(
14 [(ch.get('id'),
15 {'lcn': ch.findtext('lcn'),
16 'display-name': ch.findtext('display-name')})
17 for ch in self.tree.findall('channel')])
19 def load_programmes(self):
20 def listp(x):
21 return type(x) is type([])
23 def extract_list_without_none(xml, path):
24 return [x for x in
25 [y.text for y in xml.findall(path)]
26 if x is not None]
28 self.programmes = \
29 [filter_dict
30 ({'title': p.findtext('title'),
31 'sub-title': p.findtext('sub-title'),
32 'desc': p.findtext('desc'),
33 'categories': extract_list_without_none(p, 'category'),
34 'channel': p.get('channel'),
35 'rating': p.findtext('rating/value'),
36 'date': p.findtext('date'),
37 'subtitles': p.findtext('subtitles'),
38 'directors': extract_list_without_none(p, 'credits/director'),
39 'actors': extract_list_without_none(p, 'credits/actor'),
40 'previously-shown': None if p.find('previously-shown') is None \
41 else p.find('previously-shown').get('start', ''),
42 'start': timestamp_from_xmltv_time(p.get('start')),
43 'stop': timestamp_from_xmltv_time(p.get('stop'))},
44 lambda k,v: v is not None and (not listp(v) or v))
45 for p in self.tree.findall('programme')]
47 def tgd_channel(self, programme):
48 return self.channels[programme['channel']]['lcn']
50 def tgd_title(self, programme):
51 title = programme['title']
52 if 'date' in programme:
53 title += ' (%s)' % programme['date']
54 return title
56 def tgd_short_description(self, programme):
57 sub_title = programme.get('sub-title', '')
58 categories = ''
59 if 'categories' in programme:
60 categories += '[' + \
61 '/'.join(programme['categories']) + ']'
62 return ' '.join([sub_title, categories])
64 def tgd_description(self, programme):
65 desc = programme.get('desc', '')
66 if 'subtitles' in programme:
67 desc += ' [Subtitles]'
68 if 'previously-shown' in programme:
69 datestr = programme['previously-shown']
70 if datestr == '':
71 desc += ' [Repeat]'
72 else:
73 date = datetime.date(int(datestr[0:4]), int(datestr[4:6]), int(datestr[6:8]))
74 out = date.strftime('%x')
75 desc += ' [Repeat, last shown ' + out + ']'
76 cast = self.tgd_cast_text(programme)
77 if cast is not None:
78 desc += ' ' + cast + '.'
79 directors = self.tgd_director_text(programme)
80 if directors is not None:
81 desc += ' Dir. ' + directors + '.'
82 return desc
84 def tgd_rating(self, programme):
85 return programme.get('rating', 'X')
87 def tgd_director_text(self, programme):
88 if 'directors' in programme:
89 return ', '.join(programme['directors'])
90 else:
91 return None
93 def tgd_cast_text(self, programme):
94 if 'actors' in programme:
95 return ', '.join(programme['actors'])
96 else:
97 return None
99 def programme_to_tgd(self, programme):
100 tgd_channel = self.tgd_channel(programme)
101 tgd_start = tgd_time_from_timestamp(programme['start'])
102 duration = programme['stop'] - programme['start']
103 tgd_duration = tgd_duration_from_timedelta(duration)
104 tgd_rating = 'X'
106 line = '\t'.join([str_or_empty(x)
107 for x in [tgd_channel,
108 tgd_start,
109 tgd_duration,
110 self.tgd_title(programme),
111 self.tgd_short_description(programme),
112 self.tgd_description(programme),
113 self.tgd_rating(programme),
114 'N']])
115 return line
117 def timestamp_from_xmltv_time(timestr):
118 return datetime.datetime.strptime(timestr, '%Y%m%d%H%M%S +0000')
120 def tgd_time_from_timestamp(timestamp):
121 t = timestamp_as_localtime(timestamp)
122 return t.strftime('%Y/%m/%d %H:%M')
124 def timestamp_as_localtime(timestamp):
125 # [FUCKO]
126 return timestamp + datetime.timedelta(0, 36000 + 3600, 0)
128 def tgd_duration_from_timedelta(duration):
129 return str(duration.seconds / 60)
131 def str_or_empty(s):
132 return s if s is not None else ''
134 def filter_dict(d, predicate):
135 return dict([(k,v) for (k,v) in d.iteritems() if predicate(k,v)])
137 def tgd_filename_from_programme(programme):
138 t = timestamp_as_localtime(programme['start'])
139 return t.strftime('%Y%m%d.tgd')
141 sd_channels = ('2','22','3','7','9','10','23','32','72','99','12')
143 if __name__=='__main__':
144 filename = 'iceguide.xml'
145 parser = IceToTgd()
146 parser.use_xml_file(filename)
147 current_tgd_filename = None
148 current_tgd_file = None
149 for p in parser.programmes:
150 if parser.tgd_channel(p) in sd_channels:
151 new_tgd_filename = tgd_filename_from_programme(p)
152 if new_tgd_filename != current_tgd_filename:
153 current_tgd_file = open('out/' + new_tgd_filename, 'a')
154 try:
155 line = parser.programme_to_tgd(p).encode('UTF-8')
156 except Exception, e:
157 print 'data: "%s"' % p
158 raise e
159 current_tgd_file.write(line + '\r\n')