Initial Commit
[Projects.git] / pkgbuilds / pytivo / pkg / usr / share / pyTivo / plugins / webvideo / webvideo.py
blobb463bdc74d9c83d901b6e6b28ba645b73ca0e180
1 import Queue
2 import logging
3 import os
4 import shutil
5 import threading
6 import time
7 import urllib
8 import urllib2
9 import warnings
11 try:
12 import xml.etree.ElementTree as ElementTree
13 except ImportError:
14 try:
15 import elementtree.ElementTree as ElementTree
16 except ImportError:
17 warnings.warn('Python 2.5 or higher or elementtree is ' +
18 'needed to use the TivoPush')
20 import xmpp
21 import mind
22 import config
23 from plugins.video.video import Video, VideoDetails
24 from plugins.video.transcode import tivo_compatible
26 CLASS_NAME = 'WebVideo'
28 class WebVideo(Video):
30 CONTENT_TYPE = 'x-not-for/tivo'
32 def init(self):
33 self.__logger = logging.getLogger('pyTivo.webvideo')
34 self.work_queue = Queue.Queue()
35 self.download_thread_num = 1
36 self.in_progress = {}
37 self.in_progress_lock = threading.Lock()
39 self.startXMPP()
40 self.startWorkerThreads()
42 def startXMPP(self):
43 m = mind.getMind()
44 xmpp_info = m.getXMPPLoginInfo()
46 jid=xmpp.protocol.JID(xmpp_info['username'] + '/pyTivo')
47 cl=xmpp.Client(
48 server=xmpp_info['server'],
49 port=xmpp_info['port'],
50 debug=[],
52 self.__logger.debug('Connecting to %s:%s' % (xmpp_info['server'],
53 xmpp_info['port']))
54 cl.connect()
55 cl.RegisterHandler('message', self.processMessage)
56 self.__logger.debug('Loging in as %s/pyTivo' % xmpp_info['username'])
57 cl.auth(user=jid.getNode(), password=config.get_server('tivo_password'),
58 resource='pyTivo')
60 cl.sendInitPresence(requestRoster=0)
62 for user_name in xmpp_info['presence_list']:
63 self.__logger.debug('Sending presence to %s' % user_name)
64 jid = xmpp.protocol.JID(user_name)
65 cl.sendPresence(jid)
67 t = threading.Thread(target=self.processXMPP, args=(cl,))
68 t.setDaemon(True)
69 t.start()
71 def startWorkerThreads(self):
72 for i in range(self.download_thread_num):
73 t = threading.Thread(target=self.processDlRequest,
74 name='webvideo downloader')
75 t.setDaemon(True)
76 t.start()
78 t = threading.Thread(target=self.watchQueue,
79 name='webvideo queue watcher')
80 t.setDaemon(True)
81 t.start()
83 def processXMPP(self, client):
84 while client.Process(3):
85 pass
87 def processMessage(self, sess, mess):
88 self.__logger.debug('Got message\n %s' % mess.getBody())
89 xmpp_action = ElementTree.fromstring(mess.getBody())
91 method_name = 'xmpp_' + xmpp_action.findtext('action').lower()
92 if not hasattr(self, method_name):
93 return False
95 method = getattr(self, method_name)
96 method(xmpp_action)
98 def watchQueue(self):
99 while True:
100 self.xmpp_cdsupdate()
101 time.sleep(60*15)
103 def xmpp_cdsupdate(self, xml=None):
104 m = mind.getMind()
106 self.in_progress_lock.acquire()
107 try:
108 for request in m.getDownloadRequests():
109 if not request['bodyOfferId'] in self.in_progress:
110 self.__logger.debug('Adding request to queue, %s' % request)
111 self.in_progress[request['bodyOfferId']] = True
112 self.work_queue.put(request)
113 finally:
114 self.in_progress_lock.release()
116 def processDlRequest(self):
118 while True:
119 data = self.work_queue.get()
121 for share_name, settings in config.getShares():
122 if settings['type'] == 'webvideo':
123 break
124 self.__logger.debug('Processing request: %s' % data)
126 path = settings['path']
128 file_name = os.path.join(path, '%s-%s' %
129 (data['bodyOfferId'].replace(':', '-'),
130 data['url'].split('/')[-1]))
132 self.downloadFile(data['url'], file_name)
134 tsn = data['bodyId']
135 file_info = VideoDetails()
137 mime = ''
138 if config.isHDtivo(tsn):
139 for m in ['video/mp4', 'video/bif']:
140 if tivo_compatible(file_path, tsn, m)[0]:
141 mime = m
142 break
144 file_info.update(self.metadata_full(file_name, tsn, mime))
146 ip = config.get_ip()
147 port = config.getPort()
149 data['url'] = ('http://%s:%s' % (ip, port) +
150 urllib.quote('/%s/%s' % (share_name,
151 os.path.split(file_name)[-1])))
152 data['duration'] = file_info['duration'] / 1000
153 data['size'] = file_info['size']
155 self.__logger.debug('Complete request: %s' % data)
157 m = mind.getMind()
158 m.completeDownloadRequest(data, mime)
160 self.in_progress_lock.acquire()
161 try:
162 del self.in_progress[data['bodyOfferId']]
163 finally:
164 self.in_progress_lock.release()
166 def downloadFile(self, url, file_path):
167 self.__logger.info('Downloading %s to %s' % (url, file_path))
169 outfile = open(file_path, 'awb')
170 size = os.path.getsize(file_path)
171 r = urllib2.Request(url)
172 if size:
173 r.add_header('Range', 'bytes=%s-' % size)
175 try:
176 infile = urllib2.urlopen(r)
177 except urllib2.HTTPError, e:
178 if not e.code == 416:
179 raise
180 infile = urllib2.urlopen(url)
181 if int(infile.info()['Content-Length']) == size:
182 self.__logger.debug('File was already done. %s' % url)
183 return
184 else:
185 self.__logger.debug('File was not done but could not resume. %s'
186 % url)
187 outfile.close()
188 outfile = open(file_path, 'wb')
190 shutil.copyfileobj(infile, outfile, 8192)
192 self.__logger.info('Done downloading %s to %s' % (url, file_path))
194 def send_file(self, handler, path, query):
195 Video.send_file(self, handler, path, query)
196 if os.path.exists(path):
197 self.__logger.info('Deleting file %s' % path)
198 os.remove(path)