root/plugins/webvideo/webvideo.py

Revision 1778ab1cb1dc9b8e47928c28ca96938b4d47e28d, 5.7 kB (checked in by Jason Michalski <armooo@armooo.net>, 9 months ago)

Made the local file name safe for windows

  • Property mode set to 100644
Line 
1 from plugins.video.video import Video, VideoDetails
2 import mind
3 import config
4
5 import xmpp
6
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
19
20 CLASS_NAME = 'WebVideo'
21
22
23 class WebVideo(Video):
24
25     CONTENT_TYPE = 'x-not-for/tivo'
26
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()
33
34         self.startXMPP()
35         self.startWorkerThreads()
36
37     def startXMPP(self):
38         m = mind.getMind()
39         xmpp_info = m.getXMPPLoginInfo()
40
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=[],
46         )
47         self.__logger.debug('Connecting to %s:%s' % (xmpp_info['server'], xmpp_info['port']))
48         cl.connect()
49         cl.RegisterHandler('message', self.processMessage)
50         self.__logger.debug('Loging in as %s/pyTivo' % xmpp_info['username'])
51         cl.auth(user=jid.getNode(), password=config.getTivoPassword(), resource='pyTivo')
52
53         cl.sendInitPresence(requestRoster=0)
54
55         for user_name in xmpp_info['presence_list']:
56             self.__logger.debug('Sending presence to %s' % user_name)
57             jid=xmpp.protocol.JID(user_name)
58             cl.sendPresence(jid)
59
60         t = threading.Thread(target=self.processXMPP, args=(cl,))
61         t.setDaemon(True)
62         t.start()
63
64     def startWorkerThreads(self):
65         for i in range(self.download_thread_num):
66             t = threading.Thread(target=self.processDlRequest, name='webvideo downloader')
67             t.setDaemon(True)
68             t.start()
69
70         t = threading.Thread(target=self.watchQueue, name='webvideo queue watcher')
71         t.setDaemon(True)
72         t.start()
73
74     def processXMPP(self, client):
75         while client.Process(3):
76             pass
77
78     def processMessage(self, sess, mess):
79         self.__logger.debug('Got message\n %s' % mess.getBody())
80         xmpp_action = ElementTree.fromstring(mess.getBody())
81
82         method_name = 'xmpp_' + xmpp_action.findtext('action').lower()
83         if not hasattr(self, method_name):
84             return False
85
86         method = getattr(self, method_name)
87         method(xmpp_action)
88
89     def watchQueue(self):
90         while True:
91             self.xmpp_cdsupdate()
92             time.sleep(60*15)
93
94     def xmpp_cdsupdate(self, xml=None):
95         m = mind.getMind()
96
97         self.in_progress_lock.acquire()
98         try:
99             for request in m.getDownloadRequests():
100                 if not request['bodyOfferId'] in self.in_progress:
101                     self.__logger.debug('Adding request to queue, %s' % request)
102                     self.in_progress[request['bodyOfferId']] = True
103                     self.work_queue.put(request)
104         finally:
105             self.in_progress_lock.release()
106
107     def processDlRequest(self):
108
109         while True:
110             data = self.work_queue.get()
111
112             for share_name, settings in config.getShares():
113                 if settings['type'] == 'webvideo':
114                     break
115             self.__logger.debug('Processing request: %s' % data)
116
117             path = settings['path']
118             file_name = os.path.join(path, '%s-%s' % (data['bodyOfferId'].replace(':', '-'),data['url'].split('/')[-1]))
119
120             self.downloadFile(data['url'], file_name)
121
122             tsn = data['bodyId']
123             file_info = VideoDetails()
124             file_info.update(self.metadata_full(file_name, tsn))
125
126             import socket
127             s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
128             s.connect(('tivo.com',123))
129             ip = s.getsockname()[0]
130             port = config.getPort()
131
132             data['url'] = 'http://%s:%s' % (ip, port) + urllib.quote('/%s/%s' % (share_name, os.path.split(file_name)[-1]))
133             data['duration'] = file_info['duration'] / 1000
134             data['size'] = file_info['size']
135
136             self.__logger.debug('Complete request: %s' % data)
137
138             m = mind.getMind()
139             m.completeDownloadRequest(data)
140
141             self.in_progress_lock.acquire()
142             try:
143                 del self.in_progress[data['bodyOfferId']]
144             finally:
145                 self.in_progress_lock.release()
146
147     def downloadFile(self, url, file_path):
148         self.__logger.info('Downloading %s to %s' % (url, file_path))
149
150         outfile = open(file_path, 'awb')
151         size = os.path.getsize(file_path)
152         r = urllib2.Request(url)
153         if size:
154             r.add_header('Range', 'bytes=%s-' % size)
155
156         try:
157             infile = urllib2.urlopen(r)
158         except urllib2.HTTPError, e:
159             if not e.code == 416:
160                 raise
161             infile = urllib2.urlopen(url)
162             if int(infile.info()['Content-Length']) == size:
163                 self.__logger.debug('File was alraedy done. %s' % url)
164                 return
165             else:
166                 self.__logger.debug('File was not done but could not resume. %s' % url)
167                 outfile.close()
168                 outfile = open(file_path, 'wb')
169
170         shutil.copyfileobj(infile, outfile, 8192)
171
172         self.__logger.info('Done downloading %s to %s' % (url, file_path))
173
174     def send_file(self, handler, container, name):
175         Video.send_file(self, handler, container, name)
176
177         o = urlparse.urlparse("http://fake.host" + handler.path)
178         path = urllib.unquote(o[2])
179         file_path = container['path'] + path[len(name) + 1:]
180         if os.path.exists(file_path):
181             self.__logger.info('Deleting file %s' % file_path)
182             os.unlink(file_path)
183
Note: See TracBrowser for help on using the browser.