Encode all mpeg2video as yuv420p.
[pyTivo/wmcbrine/lucasnz.git] / plugins / webvideo / webvideo.py
blob46624e0beddff5b31a6b7626f30896cfdae3484b
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
10 import xml.etree.ElementTree as ElementTree
12 import xmpp
13 import mind
14 import config
15 from plugins.video.video import BaseVideo, VideoDetails
16 from plugins.video.transcode import tivo_compatible
18 CLASS_NAME = 'WebVideo'
20 class WebVideo(BaseVideo):
22 CONTENT_TYPE = 'x-not-for/tivo'
24 def init(self):
25 self.__logger = logging.getLogger('pyTivo.webvideo')
26 self.work_queue = Queue.Queue()
27 self.download_thread_num = 1
28 self.in_progress = {}
29 self.in_progress_lock = threading.Lock()
31 self.startXMPP()
32 self.startWorkerThreads()
34 def startXMPP(self):
35 m = mind.getMind()
36 xmpp_info = m.getXMPPLoginInfo()
38 jid=xmpp.protocol.JID(xmpp_info['username'] + '/pyTivo')
39 cl=xmpp.Client(
40 server=xmpp_info['server'],
41 port=xmpp_info['port'],
42 debug=[],
44 self.__logger.debug('Connecting to %s:%s' % (xmpp_info['server'],
45 xmpp_info['port']))
46 cl.connect()
47 cl.RegisterHandler('message', self.processMessage)
48 self.__logger.debug('Loging in as %s/pyTivo' % xmpp_info['username'])
49 cl.auth(user=jid.getNode(), password=config.get_server('tivo_password'),
50 resource='pyTivo')
52 cl.sendInitPresence(requestRoster=0)
54 for user_name in xmpp_info['presence_list']:
55 self.__logger.debug('Sending presence to %s' % user_name)
56 jid = xmpp.protocol.JID(user_name)
57 cl.sendPresence(jid)
59 t = threading.Thread(target=self.processXMPP, args=(cl,))
60 t.setDaemon(True)
61 t.start()
63 def startWorkerThreads(self):
64 for i in range(self.download_thread_num):
65 t = threading.Thread(target=self.processDlRequest,
66 name='webvideo downloader')
67 t.setDaemon(True)
68 t.start()
70 t = threading.Thread(target=self.watchQueue,
71 name='webvideo queue watcher')
72 t.setDaemon(True)
73 t.start()
75 def processXMPP(self, client):
76 while client.Process(3):
77 pass
79 def processMessage(self, sess, mess):
80 self.__logger.debug('Got message\n %s' % mess.getBody())
81 xmpp_action = ElementTree.fromstring(mess.getBody())
83 method_name = 'xmpp_' + xmpp_action.findtext('action').lower()
84 if not hasattr(self, method_name):
85 return False
87 method = getattr(self, method_name)
88 method(xmpp_action)
90 def watchQueue(self):
91 while True:
92 self.xmpp_cdsupdate()
93 time.sleep(60*15)
95 def xmpp_cdsupdate(self, xml=None):
96 m = mind.getMind()
98 self.in_progress_lock.acquire()
99 try:
100 for request in m.getDownloadRequests():
101 if not request['bodyOfferId'] in self.in_progress:
102 self.__logger.debug('Adding request to queue, %s' % request)
103 self.in_progress[request['bodyOfferId']] = True
104 self.work_queue.put(request)
105 finally:
106 self.in_progress_lock.release()
108 def processDlRequest(self):
110 while True:
111 data = self.work_queue.get()
113 for share_name, settings in config.getShares():
114 if settings['type'] == 'webvideo':
115 break
116 self.__logger.debug('Processing request: %s' % data)
118 path = settings['path']
120 file_name = os.path.join(path, '%s-%s' %
121 (data['bodyOfferId'].replace(':', '-'),
122 data['url'].split('/')[-1]))
124 status = self.downloadFile(data['url'], file_name)
125 mime = 'video/mpeg'
127 if status:
128 tsn = data['bodyId'][4:]
129 file_info = VideoDetails()
131 if config.isHDtivo(tsn):
132 for m in ['video/mp4', 'video/bif']:
133 if tivo_compatible(file_name, tsn, m)[0]:
134 mime = m
135 break
137 file_info.update(self.metadata_full(file_name, tsn, mime))
139 ip = config.get_ip()
140 port = config.getPort()
142 data['url'] = ('http://%s:%s' % (ip, port) +
143 urllib.quote('/%s/%s' % (share_name,
144 os.path.basename(file_name))))
145 data['duration'] = file_info['duration'] / 1000
146 data['size'] = file_info['size']
148 self.__logger.debug('Complete request: %s' % data)
150 m = mind.getMind()
151 m.completeDownloadRequest(data, status, mime)
153 self.in_progress_lock.acquire()
154 try:
155 del self.in_progress[data['bodyOfferId']]
156 finally:
157 self.in_progress_lock.release()
159 def downloadFile(self, url, file_path):
160 self.__logger.info('Downloading %s to %s' % (url, file_path))
162 outfile = open(file_path, 'ab')
163 size = os.path.getsize(file_path)
164 r = urllib2.Request(url)
165 if size:
166 r.add_header('Range', 'bytes=%s-' % size)
168 try:
169 infile = urllib2.urlopen(r)
170 except urllib2.HTTPError, e:
171 if not e.code == 416:
172 self.__logger.error('Downloading %s: %d' % (url, e.code))
173 outfile.close()
174 return False
175 infile = urllib2.urlopen(url)
176 if int(infile.info()['Content-Length']) == size:
177 self.__logger.debug('File was already done. %s' % url)
178 return True
179 else:
180 self.__logger.debug('File was not done but could not resume. %s'
181 % url)
182 outfile.close()
183 outfile = open(file_path, 'wb')
185 shutil.copyfileobj(infile, outfile, 8192)
187 self.__logger.info('Done downloading %s to %s' % (url, file_path))
188 return True
190 def send_file(self, handler, path, query):
191 Video.send_file(self, handler, path, query)
192 if os.path.exists(path):
193 self.__logger.info('Deleting file %s' % path)
194 os.remove(path)