10 import xml
.etree
.ElementTree
as ElementTree
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'
25 self
.__logger
= logging
.getLogger('pyTivo.webvideo')
26 self
.work_queue
= Queue
.Queue()
27 self
.download_thread_num
= 1
29 self
.in_progress_lock
= threading
.Lock()
32 self
.startWorkerThreads()
36 xmpp_info
= m
.getXMPPLoginInfo()
38 jid
=xmpp
.protocol
.JID(xmpp_info
['username'] + '/pyTivo')
40 server
=xmpp_info
['server'],
41 port
=xmpp_info
['port'],
44 self
.__logger
.debug('Connecting to %s:%s' % (xmpp_info
['server'],
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'),
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
)
59 t
= threading
.Thread(target
=self
.processXMPP
, args
=(cl
,))
63 def startWorkerThreads(self
):
64 for i
in range(self
.download_thread_num
):
65 t
= threading
.Thread(target
=self
.processDlRequest
,
66 name
='webvideo downloader')
70 t
= threading
.Thread(target
=self
.watchQueue
,
71 name
='webvideo queue watcher')
75 def processXMPP(self
, client
):
76 while client
.Process(3):
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
):
87 method
= getattr(self
, method_name
)
95 def xmpp_cdsupdate(self
, xml
=None):
98 self
.in_progress_lock
.acquire()
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
)
106 self
.in_progress_lock
.release()
108 def processDlRequest(self
):
111 data
= self
.work_queue
.get()
113 for share_name
, settings
in config
.getShares():
114 if settings
['type'] == 'webvideo':
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
)
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]:
137 file_info
.update(self
.metadata_full(file_name
, tsn
, mime
))
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
)
151 m
.completeDownloadRequest(data
, status
, mime
)
153 self
.in_progress_lock
.acquire()
155 del self
.in_progress
[data
['bodyOfferId']]
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
)
166 r
.add_header('Range', 'bytes=%s-' % size
)
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
))
175 infile
= urllib2
.urlopen(url
)
176 if int(infile
.info()['Content-Length']) == size
:
177 self
.__logger
.debug('File was already done. %s' % url
)
180 self
.__logger
.debug('File was not done but could not resume. %s'
183 outfile
= open(file_path
, 'wb')
185 shutil
.copyfileobj(infile
, outfile
, 8192)
187 self
.__logger
.info('Done downloading %s to %s' % (url
, file_path
))
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
)