Skip to content

Commit 6c9586a

Browse files
committed
MOBILE-1554 resource: Open online URL for streaming resources
1 parent 32024a5 commit 6c9586a

File tree

5 files changed

+127
-33
lines changed

5 files changed

+127
-33
lines changed

www/addons/mod_resource/services/resource.js

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ angular.module('mm.addons.mod_resource')
2222
* @name $mmaModResource
2323
*/
2424
.factory('$mmaModResource', function($mmFilepool, $mmSite, $mmUtil, $mmFS, $http, $log, $q, $sce, $mmApp, $mmSitesManager,
25-
mmaModResourceComponent) {
25+
mmaModResourceComponent, mmCoreNotDownloaded, mmCoreDownloading, mmCoreDownloaded) {
2626
$log = $log.getInstance('$mmaModResource');
2727

2828
var self = {};
@@ -356,20 +356,61 @@ angular.module('mm.addons.mod_resource')
356356
siteId = $mmSite.getId(),
357357
revision = $mmFilepool.getRevisionFromFileList(files),
358358
timeMod = $mmFilepool.getTimemodifiedFromFileList(files),
359+
component = mmaModResourceComponent,
360+
url = contents[0].fileurl,
361+
fixedUrl = $mmSite.fixPluginfileURL(url),
359362
promise;
360363

361364
if ($mmFS.isAvailable()) {
362365
// The file system is available.
363-
promise = $mmFilepool.downloadPackage(siteId, files, mmaModResourceComponent, moduleId, revision, timeMod).then(function() {
364-
return $mmFilepool.getUrlByUrl(siteId, contents[0].fileurl, mmaModResourceComponent, moduleId, timeMod);
366+
promise = $mmFilepool.getPackageStatus(siteId, component, moduleId, revision, timeMod).then(function(status) {
367+
var isWifi = !$mmApp.isNetworkAccessLimited(),
368+
isOnline = $mmApp.isOnline();
369+
370+
if (status === mmCoreDownloaded) {
371+
// Get the local file URL.
372+
return $mmFilepool.getUrlByUrl(siteId, url, component, moduleId, timeMod);
373+
} else if (status === mmCoreDownloading) {
374+
// Return the online URL.
375+
return fixedUrl;
376+
} else {
377+
if (!isOnline && status === mmCoreNotDownloaded) {
378+
// Not downloaded and we're offline, reject.
379+
return $q.reject();
380+
}
381+
382+
return $mmFilepool.shouldDownloadBeforeOpen(fixedUrl, contents[0].filesize).then(function() {
383+
// Download and then return the local URL.
384+
return $mmFilepool.downloadPackage(siteId, files, component, moduleId, revision, timeMod).then(function() {
385+
return $mmFilepool.getUrlByUrl(siteId, url, component, moduleId, timeMod);
386+
});
387+
}, function() {
388+
// Start the download if in wifi, but return the URL right away so the file is opened.
389+
if (isWifi && isOnline) {
390+
$mmFilepool.downloadPackage(siteId, files, component, moduleId, revision, timeMod);
391+
}
392+
393+
if (status === mmCoreNotDownloaded || isOnline) {
394+
// Not downloaded or outdated and online, return the online URL.
395+
return fixedUrl;
396+
} else {
397+
// Outdated but offline, so we return the local URL.
398+
return $mmFilepool.getUrlByUrl(siteId, url, component, moduleId, timeMod);
399+
}
400+
});
401+
}
365402
});
366403
} else {
367404
// We use the live URL.
368-
promise = $q.when($mmSite.fixPluginfileURL(url));
405+
promise = $q.when(fixedUrl);
369406
}
370407

371-
return promise.then(function(localUrl) {
372-
return $mmUtil.openFile(localUrl);
408+
return promise.then(function(url) {
409+
if (url.indexOf('http') === 0) {
410+
return $mmUtil.openOnlineFile(url);
411+
} else {
412+
return $mmUtil.openFile(url);
413+
}
373414
});
374415
};
375416

www/core/lib/filepool.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,37 @@ angular.module('mm.core')
23212321
});
23222322
};
23232323

2324+
/**
2325+
* Convenience function to check if a file should be downloaded before opening it.
2326+
*
2327+
* @module mm.core
2328+
* @ngdoc method
2329+
* @name $mmFilepool#shouldDownloadBeforeOpen
2330+
* @param {String} url File online URL.
2331+
* @param {Number} size File size.
2332+
* @return {Promise} Promise resolved if should download before open, rejected otherwise.
2333+
* @description
2334+
* Convenience function to check if a file should be downloaded before opening it.
2335+
*
2336+
* The default behaviour in the app is to download first and then open the local file in the following cases:
2337+
* - The file is small (less than mmFilepoolDownloadThreshold).
2338+
* - The file cannot be streamed.
2339+
* If the file is big and can be streamed, the promise returned by this function will be rejected.
2340+
*/
2341+
self.shouldDownloadBeforeOpen = function(url, size) {
2342+
if (size >= 0 && size <= mmFilepoolDownloadThreshold) {
2343+
// The file is small, download it.
2344+
return $q.when();
2345+
}
2346+
2347+
return $mmUtil.getMimeType(url).then(function(mimetype) {
2348+
// If the file is streaming (audio or video) we reject.
2349+
if (mimetype.indexOf('video') != -1 || mimetype.indexOf('audio') != -1) {
2350+
return $q.reject();
2351+
}
2352+
});
2353+
};
2354+
23242355
/**
23252356
* Store package status.
23262357
*

www/core/lib/text.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,17 @@ angular.module('mm.core')
337337
self.guessExtensionFromUrl = function(fileUrl) {
338338
var split = fileUrl.split('.'),
339339
candidate,
340-
extension;
340+
extension,
341+
position;
341342

342343
if (split.length > 1) {
343344
candidate = split.pop().toLowerCase();
345+
// Remove params if any.
346+
position = candidate.indexOf('?');
347+
if (position > -1) {
348+
candidate = candidate.substr(0, position);
349+
}
350+
344351
if (extensionRegex.test(candidate)) {
345352
extension = candidate;
346353
}

www/core/lib/util.js

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -277,20 +277,12 @@ angular.module('mm.core')
277277
* @name $mmUtil#openFile
278278
* @param {String} path The local path of the file to be open.
279279
* @return {Void}
280+
* @todo Restore node-webkit support.
280281
*/
281282
self.openFile = function(path) {
282283
var deferred = $q.defer();
283284

284-
if (false) {
285-
// TODO Restore node-webkit support.
286-
287-
// Link is the file path in the file system.
288-
// We use the node-webkit shell for open the file (pdf, doc) using the default application configured in the os.
289-
// var gui = require('nw.gui');
290-
// gui.Shell.openItem(path);
291-
deferred.resolve();
292-
293-
} else if (window.plugins) {
285+
if (window.plugins) {
294286
var extension = $mmFS.getFileExtension(path),
295287
mimetype = $mmFS.getMimeType(extension);
296288

@@ -425,30 +417,24 @@ angular.module('mm.core')
425417

426418
/**
427419
* Open an online file using platform specific method.
420+
* Specially useful for audio and video since they can be streamed.
428421
*
429422
* node-webkit: Using the default application configured.
430423
* Android: Using the WebIntent plugin.
431-
* iOs: Using the window.open method.
424+
* iOS: Using the window.open method (InAppBrowser)
425+
* We don't use iOS quickview framework because it doesn't support streaming.
432426
*
433427
* @module mm.core
434428
* @ngdoc method
435429
* @name $mmUtil#openOnlineFile
436430
* @param {String} url The URL of the file.
437431
* @return {Promise} Promise resolved when opened.
432+
* @todo Restore node-webkit support.
438433
*/
439434
self.openOnlineFile = function(url) {
440435
var deferred = $q.defer();
441436

442-
if (false) {
443-
// @todo Restore node-webkit support.
444-
445-
// Link is the file path in the file system.
446-
// We use the node-webkit shell for open the file (pdf, doc) using the default application configured in the os.
447-
// var gui = require('nw.gui');
448-
// gui.Shell.openItem(path);
449-
deferred.resolve();
450-
451-
} else if (ionic.Platform.isAndroid() && window.plugins && window.plugins.webintent) {
437+
if (ionic.Platform.isAndroid() && window.plugins && window.plugins.webintent) {
452438
// In Android we need the mimetype to open it.
453439
var extension,
454440
iParams;
@@ -496,6 +482,27 @@ angular.module('mm.core')
496482
return deferred.promise;
497483
};
498484

485+
/**
486+
* Get the mimetype of a file given its URL. It'll perform a HEAD request to get it, if that
487+
* fails it'll try to guess it using the URL.
488+
*
489+
* @module mm.core
490+
* @ngdoc method
491+
* @name $mmUtil#getMimeType
492+
* @param {String} url The URL of the file.
493+
* @return {Promise} Promise resolved with the mimetype.
494+
*/
495+
self.getMimeType = function(url) {
496+
return $mmWS.getRemoteFileMimeType(url).then(function(mimetype) {
497+
if (!mimetype) {
498+
// Couldn't retireve mimetype. Try to guess it.
499+
extension = $mmText.guessExtensionFromUrl(url);
500+
mimetype = $mmFS.getMimeType(extension);
501+
}
502+
return mimetype || '';
503+
});
504+
};
505+
499506
/**
500507
* Displays a loading modal window.
501508
*

www/core/lib/ws.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ angular.module('mm.core')
2626

2727
$log = $log.getInstance('$mmWS');
2828

29-
var self = {};
29+
var self = {},
30+
mimeTypeCache = {}; // A "cache" to store file mimetypes to prevent performing too many HEAD requests.
3031

3132
/**
3233
* A wrapper function for a moodle WebService call.
@@ -237,12 +238,19 @@ angular.module('mm.core')
237238
* @module mm.core
238239
* @ngdoc method
239240
* @name $mmWS#getRemoteFileMimeType
240-
* @param {Object} url File URL.
241-
* @return {Promise} Promise resolved with the mimetype or '' if failure.
241+
* @param {Object} url File URL.
242+
* @param {Boolean} ignoreCache True to ignore cache, false otherwise.
243+
* @return {Promise} Promise resolved with the mimetype or '' if failure.
242244
*/
243-
self.getRemoteFileMimeType = function(url) {
245+
self.getRemoteFileMimeType = function(url, ignoreCache) {
246+
if (mimeTypeCache[url] && !ignoreCache) {
247+
promise = $q.when(mimeTypeCache[url]);
248+
}
249+
244250
return $http.head(url).then(function(data) {
245-
return data.headers('Content-Type') || '';
251+
var mimeType = data.headers('Content-Type');
252+
mimeTypeCache[url] = mimeType;
253+
return mimeType || '';
246254
}).catch(function() {
247255
return '';
248256
});

0 commit comments

Comments
 (0)