12 import xml
.etree
.ElementTree
as ElementTree
15 import elementtree
.ElementTree
as ElementTree
17 warnings
.warn('Python 2.5 or higher or elementtree is ' +
18 'needed to use the TivoPush')
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'
33 self
.__logger
= logging
.getLogger('pyTivo.webvideo')
34 self
.work_queue
= Queue
.Queue()
35 self
.download_thread_num
= 1
37 self
.in_progress_lock
= threading
.Lock()
40 self
.startWorkerThreads()
44 xmpp_info
= m
.getXMPPLoginInfo()
46 jid
=xmpp
.protocol
.JID(xmpp_info
['username'] + '/pyTivo')
48 server
=xmpp_info
['server'],
49 port
=xmpp_info
['port'],
52 self
.__logger
.debug('Connecting to %s:%s' % (xmpp_info
['server'],
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'),
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
)
67 t
= threading
.Thread(target
=self
.processXMPP
, args
=(cl
,))
71 def startWorkerThreads(self
):
72 for i
in range(self
.download_thread_num
):
73 t
= threading
.Thread(target
=self
.processDlRequest
,
74 name
='webvideo downloader')
78 t
= threading
.Thread(target
=self
.watchQueue
,
79 name
='webvideo queue watcher')
83 def processXMPP(self
, client
):
84 while client
.Process(3):
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
):
95 method
= getattr(self
, method_name
)
100 self
.xmpp_cdsupdate()
103 def xmpp_cdsupdate(self
, xml
=None):
106 self
.in_progress_lock
.acquire()
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
)
114 self
.in_progress_lock
.release()
116 def processDlRequest(self
):
119 data
= self
.work_queue
.get()
121 for share_name
, settings
in config
.getShares():
122 if settings
['type'] == 'webvideo':
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
)
135 file_info
= VideoDetails()
138 if config
.isHDtivo(tsn
):
139 for m
in ['video/mp4', 'video/bif']:
140 if tivo_compatible(file_path
, tsn
, m
)[0]:
144 file_info
.update(self
.metadata_full(file_name
, tsn
, mime
))
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
)
158 m
.completeDownloadRequest(data
, mime
)
160 self
.in_progress_lock
.acquire()
162 del self
.in_progress
[data
['bodyOfferId']]
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
)
173 r
.add_header('Range', 'bytes=%s-' % size
)
176 infile
= urllib2
.urlopen(r
)
177 except urllib2
.HTTPError
, e
:
178 if not e
.code
== 416:
180 infile
= urllib2
.urlopen(url
)
181 if int(infile
.info()['Content-Length']) == size
:
182 self
.__logger
.debug('File was already done. %s' % url
)
185 self
.__logger
.debug('File was not done but could not resume. %s'
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
)