General routine for metadata from container XML; put seriesId back.
[pyTivo/TheBayer.git] / metadata.py
blobd6f256b3343cf6d19f91e1ddc8f6e0f44222a956
1 import os
2 import subprocess
3 from datetime import datetime
4 from xml.dom import minidom
6 from lrucache import LRUCache
8 import config
10 # Something to strip
11 TRIBUNE_CR = ' Copyright Tribune Media Services, Inc.'
13 tivo_cache = LRUCache(50)
15 def tag_data(element, tag):
16 for name in tag.split('/'):
17 new_element = element.getElementsByTagName(name)
18 if not new_element:
19 return ''
20 element = new_element[0]
21 if not element.firstChild:
22 return ''
23 return element.firstChild.data
25 def _vtag_data(element, tag):
26 for name in tag.split('/'):
27 new_element = element.getElementsByTagName(name)
28 if not new_element:
29 return []
30 element = new_element[0]
31 elements = element.getElementsByTagName('element')
32 return [x.firstChild.data for x in elements if x.firstChild]
34 def _tag_value(element, tag):
35 item = element.getElementsByTagName(tag)
36 if item:
37 value = item[0].attributes['value'].value
38 name = item[0].firstChild.data
39 return name[0] + value[0]
41 def from_text(full_path):
42 metadata = {}
43 path, name = os.path.split(full_path)
44 for metafile in [os.path.join(path, 'default.txt'), full_path + '.txt',
45 os.path.join(path, '.meta', name) + '.txt']:
46 if os.path.exists(metafile):
47 for line in file(metafile):
48 if line.strip().startswith('#') or not ':' in line:
49 continue
50 key, value = [x.strip() for x in line.split(':', 1)]
51 if key.startswith('v'):
52 if key in metadata:
53 metadata[key].append(value)
54 else:
55 metadata[key] = [value]
56 else:
57 metadata[key] = value
58 return metadata
60 def basic(full_path):
61 base_path, title = os.path.split(full_path)
62 mtime = os.stat(full_path).st_mtime
63 if (mtime < 0):
64 mtime = 0
65 originalAirDate = datetime.fromtimestamp(mtime)
67 metadata = {'title': '.'.join(title.split('.')[:-1]),
68 'originalAirDate': originalAirDate.isoformat()}
70 metadata.update(from_text(full_path))
72 return metadata
74 def from_container(xmldoc):
75 metadata = {}
77 keys = {'title': 'Title', 'episodeTitle': 'EpisodeTitle',
78 'description': 'Description', 'seriesId': 'SeriesId',
79 'episodeNumber': 'EpisodeNumber', 'tvRating': 'TvRating',
80 'displayMajorNumber': 'SourceChannel', 'callsign': 'SourceStation'}
82 details = xmldoc.getElementsByTagName('Details')[0]
84 for key in keys:
85 data = tag_data(details, keys[key])
86 if data:
87 if key == 'description':
88 data = data.replace(TRIBUNE_CR, '')
89 elif key == 'tvRating':
90 data = 'x' + data
91 elif key == 'displayMajorNumber':
92 if '-' in data:
93 data, metadata['displayMinorNumber'] = data.split('-')
94 metadata[key] = data
96 return metadata
98 def from_details(xmldoc):
99 metadata = {}
101 showing = xmldoc.getElementsByTagName('showing')[0]
102 program = showing.getElementsByTagName('program')[0]
104 items = {'description': 'program/description',
105 'title': 'program/title',
106 'episodeTitle': 'program/episodeTitle',
107 'episodeNumber': 'program/episodeNumber',
108 'seriesId': 'program/series/uniqueId',
109 'seriesTitle': 'program/series/seriesTitle',
110 'originalAirDate': 'program/originalAirDate',
111 'isEpisode': 'program/isEpisode',
112 'movieYear': 'program/movieYear',
113 'partCount': 'partCount',
114 'partIndex': 'partIndex'}
116 for item in items:
117 data = tag_data(showing, item)
118 if data:
119 if item == 'description':
120 data = data.replace(TRIBUNE_CR, '')
121 metadata[item] = data
123 vItems = ['vActor', 'vChoreographer', 'vDirector',
124 'vExecProducer', 'vProgramGenre', 'vGuestStar',
125 'vHost', 'vProducer', 'vWriter']
127 for item in vItems:
128 data = _vtag_data(program, item)
129 if data:
130 metadata[item] = data
132 sb = showing.getElementsByTagName('showingBits')
133 if sb:
134 metadata['showingBits'] = sb[0].attributes['value'].value
136 for tag in ['starRating', 'mpaaRating', 'colorCode']:
137 value = _tag_value(program, tag)
138 if value:
139 metadata[tag] = value
141 rating = _tag_value(showing, 'tvRating')
142 if rating:
143 metadata['tvRating'] = 'x' + rating[1]
145 return metadata
147 def from_tivo(full_path):
148 if full_path in tivo_cache:
149 return tivo_cache[full_path]
151 tdcat_path = config.get_bin('tdcat')
152 tivo_mak = config.get_server('tivo_mak')
153 if tdcat_path and tivo_mak:
154 tcmd = [tdcat_path, '-m', tivo_mak, '-2', full_path]
155 tdcat = subprocess.Popen(tcmd, stdout=subprocess.PIPE)
156 xmldoc = minidom.parse(tdcat.stdout)
157 metadata = from_details(xmldoc)
158 tivo_cache[full_path] = metadata
159 else:
160 metadata = {}
162 return metadata