Ticket #289: appletrailers_storage.py

File appletrailers_storage.py, 7.3 kB (added by karatsu, 2 years ago)

Custom Apple Trailer

Line 
1 # -*- coding: utf-8 -*-
2
3 # Licensed under the MIT license
4 # http://opensource.org/licenses/mit-license.php
5
6 # Copyright 2008, Benjamin Kampmann <ben.kampmann@googlemail.com>
7
8 """
9 This is a Media Backend that allows you to access the Trailers from Apple.com
10 """
11
12 from coherence.backend import BackendItem, BackendStore
13 from coherence.upnp.core import DIDLLite
14 from coherence.upnp.core.utils import ReverseProxyUriResource
15 from twisted.web import client
16 from twisted.internet import task, reactor
17
18 from coherence.extern.et import parse_xml
19
20 # XML_URL = "http://www.apple.com/trailers/home/xml/current.xml"
21 XML_URL =  "http://www.apple.com/trailers/home/xml/current_720p.xml"
22
23 ROOT_ID = 0
24
25 class AppleTrailerProxy(ReverseProxyUriResource):
26
27     def __init__(self, uri):
28         ReverseProxyUriResource.__init__(self, uri)
29
30     def render(self, request):
31         request.received_headers['user-agent'] = 'QuickTime/7.6.2 (qtver=7.6.2;os=Windows NT 5.1Service Pack 3)'
32         return ReverseProxyUriResource.render(self, request)
33
34
35 class Trailer(BackendItem):
36
37     def __init__(self, parent_id, urlbase, id=None, name=None, cover=None,
38             url=None):
39         self.parentid = parent_id
40         self.id = id
41         self.name = name
42         self.cover = cover
43         if( len(urlbase) and urlbase[-1] != '/'):
44             urlbase += '/'
45         self.url = urlbase + str(self.id)
46         self.location = AppleTrailerProxy(url)
47         self.item = DIDLLite.VideoItem(id, parent_id, self.name)
48         self.item.albumArtURI = self.cover
49
50     def get_path(self):
51         return self.url
52
53
54 class Container(BackendItem):
55
56     logCategory = 'apple_trailers'
57
58     def __init__(self, id, parent_id, name, store=None, \
59             children_callback=None):
60         self.id = id
61         self.parent_id = parent_id
62         self.name = name
63         self.mimetype = 'directory'
64         self.update_id = 0
65         self.children = []
66
67         self.item = DIDLLite.Container(id, parent_id, self.name)
68         self.item.childCount = None #self.get_child_count()
69
70     def get_children(self, start=0, end=0):
71         if(end - start > 25 or
72            start - end == start or
73            end - start == 0):
74             end = start+25
75         if end != 0:
76             return self.children[start:end]
77         return self.children[start:]
78
79     def get_child_count(self):
80         return len(self.children)
81
82     def get_item(self):
83         return self.item
84
85     def get_name(self):
86         return self.name
87
88     def get_id(self):
89         return self.id
90
91 class AppleTrailersStore(BackendStore):
92
93     logCategory = 'apple_trailers'
94     implements = ['MediaServer']
95
96     def __init__(self, server, *args, **kwargs):
97         BackendStore.__init__(self,server,**kwargs)
98         self.next_id = 1000
99         self.name = kwargs.get('name','Apple Trailers')
100         self.refresh = int(kwargs.get('refresh', 8)) * (60 *60)
101
102         self.trailers = {}
103
104         self.wmc_mapping = {'15': 0}
105
106         dfr = self.update_data()
107         # first get the first bunch of data before sending init_completed
108         dfr.addCallback(lambda x: self.init_completed())
109
110     def queue_update(self, result):
111         reactor.callLater(self.refresh, self.update_data)
112         return result
113
114     def update_data(self):
115         dfr = client.getPage(XML_URL)
116         dfr.addCallback(parse_xml)
117         dfr.addCallback(self.parse_data)
118         dfr.addCallback(self.queue_update)
119         return dfr
120
121     def parse_data(self, xml_data):
122
123         def iterate(root):
124             for item in root.findall('./movieinfo'):
125                 trailer = self._parse_into_trailer(item)
126                 yield trailer
127
128         root = xml_data.getroot()
129         return task.coiterate(iterate(root))
130
131     def _parse_into_trailer(self, item):
132         """
133         info = item.find('info')
134
135         for attr in ('title', 'runtime', 'rating', 'studio', 'postdate',
136                      'releasedate', 'copyright', 'director', 'description'):
137             setattr(trailer, attr, info.find(attr).text)
138         """
139
140         data = {}
141         data['id'] = item.get('id')
142         data['name'] = item.find('./info/title').text
143         data['cover'] = item.find('./poster/location').text
144         data['url'] = item.find('./preview/large').text.replace('movies.','',1)
145
146         trailer = Trailer(ROOT_ID, self.urlbase, **data)
147         duration = None
148         try:
149             hours = 0
150             minutes = 0
151             seconds = 0
152             duration = item.find('./info/runtime').text
153             try:
154                 hours,minutes,seconds = duration.split(':')
155             except ValueError:
156                 try:
157                     minutes,seconds = duration.split(':')
158                 except ValueError:
159                     seconds = duration
160             duration = "%d:%02d:%02d" % (int(hours), int(minutes), int(seconds))
161         except:
162             pass
163
164         try:
165             trailer.item.director = item.find('./info/director').text
166         except:
167             pass
168
169         try:
170             trailer.item.description = item.find('./info/description').text
171         except:
172             pass
173
174         res = DIDLLite.Resource(trailer.get_path(), 'http-get:*:video/mp4:*')
175         res.duration = duration
176         try:
177             res.size = item.find('./preview/large').get('filesize',None)
178         except:
179             pass
180         trailer.item.res.append(res)
181
182         if self.server.coherence.config.get('transcoding', 'no') == 'yes':
183             # dlna_pn = 'DLNA.ORG_PN=AVC_TS_BL_CIF15_AAC'
184             # dlna_tags = DIDLLite.simple_dlna_tags[:]
185             # dlna_tags[2] = 'DLNA.ORG_CI=1'
186             # url = self.urlbase + str(trailer.id)+'?transcoded=mp4'
187             # new_res = DIDLLite.Resource(url,
188             #    'http-get:*:%s:%s' % ('video/mp4', ';'.join([dlna_pn]+dlna_tags)))
189             # new_res.size = None
190             # res.duration = duration
191             # trailer.item.res.append(new_res)
192
193             dlna_pn = 'DLNA.ORG_PN=JPEG_TN'
194             dlna_tags = DIDLLite.simple_dlna_tags[:]
195             dlna_tags[2] = 'DLNA.ORG_CI=1'
196             dlna_tags[3] = 'DLNA.ORG_FLAGS=00f00000000000000000000000000000'
197             url = self.urlbase + str(trailer.id)+'?attachment=poster&transcoded=thumb&type=jpeg'
198             new_res = DIDLLite.Resource(url,
199                 'http-get:*:%s:%s' % ('image/jpeg', ';'.join([dlna_pn] + dlna_tags)))
200             new_res.size = None
201             #new_res.resolution = "160x160"
202             trailer.item.res.append(new_res)
203             if not hasattr(trailer.item, 'attachments'):
204                 trailer.item.attachments = {}
205             trailer.item.attachments['poster'] = data['cover']
206
207         self.trailers[trailer.id] = trailer
208
209     def get_by_id(self, id):
210         try:
211             if int(id) == 0:
212                 return self.container
213             else:
214                 return self.trailers.get(id,None)
215         except:
216             return None
217
218     def upnp_init(self):
219         if self.server:
220             self.server.connection_manager_server.set_variable( \
221                 0, 'SourceProtocolInfo', ['http-get:*:video/quicktime:*','http-get:*:video/mp4:*','http-get:*:video/m4v:*'])
222         self.container = Container(ROOT_ID, -1, self.name)
223         trailers = self.trailers.values()
224         trailers.sort(cmp=lambda x,y : cmp(x.get_name().lower(),y.get_name().lower()))
225         self.container.children = trailers
226
227     def __repr__(self):
228         return self.__class__.__name__