80 columns, spacing and line continuations.
[pyTivo/wgw.git] / plugins / webvideo / webvideo.py
blob89b8c8fb8387ff938f363ed63a7d9212d6f90820
1 from plugins.video.video import Video, VideoDetails
2 import mind
3 import config
5 import xmpp
7 import threading
8 import urllib2
9 import os.path
10 import shutil
11 import os.path
12 import time
13 import os
14 import urlparse
15 import urllib
16 import xml.etree.ElementTree as ElementTree
17 import Queue
18 import logging
20 CLASS_NAME = 'WebVideo'
23 class WebVideo(Video):
25 CONTENT_TYPE = 'x-not-for/tivo'
27 def init(self):
28 self.__logger = logging.getLogger('pyTivo.webvideo')
29 self.work_queue = Queue.Queue()
30 self.download_thread_num = 1
31 self.in_progress = {}
32 self.in_progress_lock = threading.Lock()
34 self.startXMPP()
35 self.startWorkerThreads()
37 def startXMPP(self):
38 m = mind.getMind()
39 xmpp_info = m.getXMPPLoginInfo()
41 jid=xmpp.protocol.JID(xmpp_info['username'] + '/pyTivo')
42 cl=xmpp.Client(
43 server=xmpp_info['server'],
44 port=xmpp_info['port'],
45 debug=[],
47 self.__logger.debug('Connecting to %s:%s' % (xmpp_info['server'],
48 xmpp_info['port']))
49 cl.connect()
50 cl.RegisterHandler('message', self.processMessage)
51 self.__logger.debug('Loging in as %s/pyTivo' % xmpp_info['username'])
52 cl.auth(user=jid.getNode(), password=config.getTivoPassword(),
53 resource='pyTivo')
55 cl.sendInitPresence(requestRoster=0)
57 for user_name in xmpp_info['presence_list']:
58 self.__logger.debug('Sending presence to %s' % user_name)
59 jid=xmpp.protocol.JID(user_name)
60 cl.sendPresence(jid)
62 t = threading.Thread(target=self.processXMPP, args=(cl,))
63 t.setDaemon(True)
64 t.start()
66 def startWorkerThreads(self):
67 for i in range(self.download_thread_num):
68 t = threading.Thread(target=self.processDlRequest,
69 name='webvideo downloader')
70 t.setDaemon(True)
71 t.start()
73 t = threading.Thread(target=self.watchQueue,
74 name='webvideo queue watcher')
75 t.setDaemon(True)
76 t.start()
78 def processXMPP(self, client):
79 while client.Process(3):
80 pass
82 def processMessage(self, sess, mess):
83 self.__logger.debug('Got message\n %s' % mess.getBody())
84 xmpp_action = ElementTree.fromstring(mess.getBody())
86 method_name = 'xmpp_' + xmpp_action.findtext('action').lower()
87 if not hasattr(self, method_name):
88 return False
90 method = getattr(self, method_name)
91 method(xmpp_action)
93 def watchQueue(self):
94 while True:
95 self.xmpp_cdsupdate()
96 time.sleep(60*15)
98 def xmpp_cdsupdate(self, xml=None):
99 m = mind.getMind()
101 self.in_progress_lock.acquire()
102 try:
103 for request in m.getDownloadRequests():
104 if not request['bodyOfferId'] in self.in_progress:
105 self.__logger.debug('Adding request to queue, %s' % request)
106 self.in_progress[request['bodyOfferId']] = True
107 self.work_queue.put(request)
108 finally:
109 self.in_progress_lock.release()
111 def processDlRequest(self):
113 while True:
114 data = self.work_queue.get()
116 for share_name, settings in config.getShares():
117 if settings['type'] == 'webvideo':
118 break
119 self.__logger.debug('Processing request: %s' % data)
121 path = settings['path']
123 file_name = os.path.join(path, '%s-%s' %
124 (data['bodyOfferId'].replace(':', '-'),
125 data['url'].split('/')[-1]))
127 self.downloadFile(data['url'], file_name)
129 tsn = data['bodyId']
130 file_info = VideoDetails()
131 file_info.update(self.metadata_full(file_name, tsn))
133 import socket
134 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
135 s.connect(('tivo.com',123))
136 ip = s.getsockname()[0]
137 port = config.getPort()
139 data['url'] = 'http://%s:%s' % (ip, port) + \
140 urllib.quote('/%s/%s' % (share_name,
141 os.path.split(file_name)[-1]))
142 data['duration'] = file_info['duration'] / 1000
143 data['size'] = file_info['size']
145 self.__logger.debug('Complete request: %s' % data)
147 m = mind.getMind()
148 m.completeDownloadRequest(data)
150 self.in_progress_lock.acquire()
151 try:
152 del self.in_progress[data['bodyOfferId']]
153 finally:
154 self.in_progress_lock.release()
156 def downloadFile(self, url, file_path):
157 self.__logger.info('Downloading %s to %s' % (url, file_path))
159 outfile = open(file_path, 'awb')
160 size = os.path.getsize(file_path)
161 r = urllib2.Request(url)
162 if size:
163 r.add_header('Range', 'bytes=%s-' % size)
165 try:
166 infile = urllib2.urlopen(r)
167 except urllib2.HTTPError, e:
168 if not e.code == 416:
169 raise
170 infile = urllib2.urlopen(url)
171 if int(infile.info()['Content-Length']) == size:
172 self.__logger.debug('File was alraedy done. %s' % url)
173 return
174 else:
175 self.__logger.debug('File was not done but could not resume. %s'
176 % url)
177 outfile.close()
178 outfile = open(file_path, 'wb')
180 shutil.copyfileobj(infile, outfile, 8192)
182 self.__logger.info('Done downloading %s to %s' % (url, file_path))
184 def send_file(self, handler, container, name):
185 Video.send_file(self, handler, container, name)
187 o = urlparse.urlparse("http://fake.host" + handler.path)
188 path = urllib.unquote(o[2])
189 file_path = container['path'] + path[len(name) + 1:]
190 if os.path.exists(file_path):
191 self.__logger.info('Deleting file %s' % file_path)
192 os.unlink(file_path)