From: Dermot Duffy <dermot.duffy@gmail.com> Date: Sun, 14 Aug 2016 00:52:20 +0000 (+0100) Subject: Back out full support for HTTP Range. X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=b3ea5371d0d0817e4ec9476a7036e3630cf900be;p=motioneye-debian Back out full support for HTTP Range. Simplify the code by removing Range support. Seeking will thus not function until the movie has been downloaded. --- diff --git a/motioneye/handlers.py b/motioneye/handlers.py index 549d8f4..f36f745 100644 --- a/motioneye/handlers.py +++ b/motioneye/handlers.py @@ -24,9 +24,8 @@ import re import socket import subprocess -from tornado import httputil from tornado.ioloop import IOLoop -from tornado.web import RequestHandler, StaticFileHandler, HTTPError, asynchronous +from tornado.web import RequestHandler, HTTPError, asynchronous import config import mediafiles @@ -979,7 +978,7 @@ class PictureHandler(BaseHandler): self.set_header('Content-Type', 'image/jpeg') self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';') - self.finish(response.body) + self.finish(response) remote.get_media_content(camera_config, filename=filename, media_type='picture', callback=on_response) @@ -1340,78 +1339,28 @@ class MovieHandler(BaseHandler): 'filename': filename, 'id': camera_id}) camera_config = config.get_camera(camera_id) - - # To facilitiate cross-browser HTML5 <video> playback we need - # to support HTTP Range requests. - # (The below adapted from Tornado's StaticFileHandler) - request_range = None - range_header = self.request.headers.get("Range") - if range_header: - request_range = httputil._parse_request_range(range_header) - if utils.local_motion_camera(camera_config): - full_path = os.path.join(camera_config.get('target_dir'), filename) - size = os.stat(full_path).st_size - if request_range: - start, end = request_range - if (start is not None and start >= size) or end == 0: - raise HTTPError(416, 'Range not satisfiable') - if start is not None and start < 0: - start += size - if end is not None and end > size: - end = size - # Chrome won't allow seeking unless we always return 206 for Range requests, - # even if this represents the entire file. - self.set_status(206) # Partial Content - self.set_header("Content-Range", httputil._get_content_range(start, end, size)) - else: - start = end = None - - if start is not None and end is not None: - content_length = end - start - elif end is not None: - content_length = end - elif start is not None: - content_length = size - start - else: - content_length = size + content = mediafiles.get_media_content(camera_config, filename, 'movie') pretty_filename = camera_config['@name'] + '_' + os.path.basename(filename) - self.set_header('Content-Type', mimetypes.guess_type(full_path)[0] or 'video/mpeg') + self.set_header('Content-Type', mimetypes.guess_type(filename)[0] or 'video/mpeg') self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';') - self.set_header("Content-Length", content_length) - - # Yield the data to the network in chunks. - content = StaticFileHandler.get_content(full_path, start, end) - if content: - for chunk in content: - try: - self.write(chunk) - self.flush() - except iostream.StreamClosedError: - return - self.finish() + + self.finish(content) elif utils.remote_camera(camera_config): def on_response(response=None, error=None): if error: return self.finish_json({'error': 'Failed to download movie from %(url)s: %(msg)s.' % { 'url': remote.pretty_camera_url(camera_config), 'msg': error}}) - # Copy certain critical headers out of the remote response and - # into our response. Propogating these headers are necessary to - # support in-brower playback of remote movies. Also copy the - # response code which might be 200 or 206 (partial content, for range - # requests). - self.set_status(response.code) - for header in ('Content-Type', 'Content-Range', 'Content-Length', 'Content-Disposition'): - if header in response.headers: - self.set_header(header, response.headers[header]) - self.finish(response.body) - - start = end = None - if request_range: - start, end = request_range - remote.get_media_content(camera_config, filename=filename, media_type='movie', callback=on_response, start=start, end=end) + + pretty_filename = os.path.basename(filename) # no camera name available w/o additional request + self.set_header('Content-Type', 'video/mpeg') + self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';') + + self.finish(response) + + remote.get_media_content(camera_config, filename=filename, media_type='movie', callback=on_response) else: # assuming simple mjpeg camera raise HTTPError(400, 'unknown operation') diff --git a/motioneye/remote.py b/motioneye/remote.py index 2d1757b..74e6217 100644 --- a/motioneye/remote.py +++ b/motioneye/remote.py @@ -379,7 +379,7 @@ def list_media(local_config, media_type, prefix, callback): http_client.fetch(request, _callback_wrapper(on_response)) -def get_media_content(local_config, filename, media_type, callback, start=None, end=None): +def get_media_content(local_config, filename, media_type, callback): scheme, host, port, username, password, path, camera_id = _remote_params(local_config) logging.debug('downloading file %(filename)s of remote camera %(id)s on %(url)s' % { @@ -391,18 +391,11 @@ def get_media_content(local_config, filename, media_type, callback, start=None, 'media_type': media_type, 'id': camera_id, 'filename': filename} - + # timeout here is 10 times larger than usual - we expect a big delay when fetching the media list request = _make_request(scheme, host, port, username, password, path, timeout=10 * settings.REMOTE_REQUEST_TIMEOUT) - - if start is not None or end is not None: - end_str = '' - start = start or 0 - if end: - end_str = str(end - 1) - request.headers['Range'] = 'bytes=%i-%s' % (start, end_str) - + def on_response(response): if response.error: logging.error('failed to download file %(filename)s of remote camera %(id)s on %(url)s: %(msg)s' % { @@ -413,7 +406,7 @@ def get_media_content(local_config, filename, media_type, callback, start=None, return callback(error=utils.pretty_http_error(response)) - return callback(response) + return callback(response.body) http_client = AsyncHTTPClient() http_client.fetch(request, _callback_wrapper(on_response)) diff --git a/motioneye/static/js/main.js b/motioneye/static/js/main.js index 98fd6ea..21f420f 100644 --- a/motioneye/static/js/main.js +++ b/motioneye/static/js/main.js @@ -2926,11 +2926,11 @@ function runPictureDialog(entries, pos, mediaType) { }); video_container.hide() content.append(video_container); - + var prevArrow = $('<div class="picture-dialog-prev-arrow button mouse-effect" title="previous picture"></div>'); content.append(prevArrow); - var playButton = $('<div class="picture-dialog-play button mouse-effect" title="play"></div>'); + var playButton = $('<div class="picture-dialog-play button mouse-effect" title="play"></div>'); content.append(playButton); var nextArrow = $('<div class="picture-dialog-next-arrow button mouse-effect" title="next picture"></div>'); @@ -2951,7 +2951,7 @@ function runPictureDialog(entries, pos, mediaType) { prevArrow.css('display', 'none'); nextArrow.css('display', 'none'); - /* Construct a likely mime-type with 'video/' and the file extension, then see if the + /* Construct a likely mime-type with 'video/' and the file extension, then see if the browser can play it */ var playable = video_container.get(0).canPlayType(entry.mimeType) != '' playButton.hide();