| Index: ui/file_manager/file_manager/background/js/media_scanner.js
|
| diff --git a/ui/file_manager/file_manager/background/js/media_scanner.js b/ui/file_manager/file_manager/background/js/media_scanner.js
|
| index 4a6227dedbf9d362cb12be7406ea666c3ce2ad25..02e411e5ceb444eb9b5636f9bcd9724e668f429e 100644
|
| --- a/ui/file_manager/file_manager/background/js/media_scanner.js
|
| +++ b/ui/file_manager/file_manager/background/js/media_scanner.js
|
| @@ -12,11 +12,22 @@ importer.MediaScanner = function() {};
|
| /**
|
| * Initiates scanning.
|
| *
|
| - * @param {!Array.<!Entry>} entries Must be non-empty.
|
| + * @param {!DirectoryEntry} directory
|
| * @return {!importer.ScanResult} ScanResult object representing the scan
|
| * job both while in-progress and when completed.
|
| */
|
| -importer.MediaScanner.prototype.scan;
|
| +importer.MediaScanner.prototype.scanDirectory;
|
| +
|
| +/**
|
| + * Initiates scanning.
|
| + *
|
| + * @param {!Array<!FileEntry>} entries Must be non-empty, and all entires
|
| + * must be of a supported media type. Individually supplied files
|
| + * are not subject to deduplication.
|
| + * @return {!importer.ScanResult} ScanResult object representing the scan
|
| + * job for the explicitly supplied entries.
|
| + */
|
| +importer.MediaScanner.prototype.scanFiles;
|
|
|
| /**
|
| * Adds an observer, which will be notified on scan events.
|
| @@ -57,7 +68,7 @@ importer.DefaultMediaScanner =
|
| return new importer.DefaultScanResult(hashGenerator);
|
| };
|
|
|
| - /** @private {!Array.<!importer.ScanObserver>} */
|
| + /** @private {!Array<!importer.ScanObserver>} */
|
| this.observers_ = [];
|
|
|
| /**
|
| @@ -90,11 +101,35 @@ importer.DefaultMediaScanner.prototype.removeObserver = function(observer) {
|
| };
|
|
|
| /** @override */
|
| -importer.DefaultMediaScanner.prototype.scan = function(entries) {
|
| - if (entries.length == 0) {
|
| - throw new Error('Cannot scan empty list of entries.');
|
| - }
|
| +importer.DefaultMediaScanner.prototype.scanDirectory = function(directory) {
|
| + var scan = this.createScanResult_();
|
| + var watcher = this.watcherFactory_(
|
| + /** @this {importer.DefaultMediaScanner} */
|
| + function() {
|
| + scan.invalidateScan();
|
| + this.notify_(importer.ScanEvent.INVALIDATED, scan);
|
| + }.bind(this));
|
| +
|
| + this.crawlDirectory_(directory, watcher)
|
| + .then(this.scanMediaFiles_.bind(this, scan))
|
| + .then(scan.resolve)
|
| + .catch(scan.reject);
|
| +
|
| + scan.whenFinal()
|
| + .then(
|
| + /** @this {importer.DefaultMediaScanner} */
|
| + function() {
|
| + this.notify_(importer.ScanEvent.FINALIZED, scan);
|
| + }.bind(this));
|
|
|
| + return scan;
|
| +};
|
| +
|
| +/** @override */
|
| +importer.DefaultMediaScanner.prototype.scanFiles = function(entries) {
|
| + if (entries.length === 0) {
|
| + throw new Error('Cannot scan empty list.');
|
| + }
|
| var scan = this.createScanResult_();
|
| var watcher = this.watcherFactory_(
|
| /** @this {importer.DefaultMediaScanner} */
|
| @@ -103,8 +138,7 @@ importer.DefaultMediaScanner.prototype.scan = function(entries) {
|
| this.notify_(importer.ScanEvent.INVALIDATED, scan);
|
| }.bind(this));
|
|
|
| - var scanPromises = entries.map(
|
| - this.scanEntry_.bind(this, scan, watcher));
|
| + var scanPromises = entries.map(this.onUniqueFileFound_.bind(this, scan));
|
|
|
| Promise.all(scanPromises)
|
| .then(scan.resolve)
|
| @@ -120,6 +154,40 @@ importer.DefaultMediaScanner.prototype.scan = function(entries) {
|
| return scan;
|
| };
|
|
|
| +/** @const {number} */
|
| +importer.DefaultMediaScanner.SCAN_BATCH_SIZE = 1;
|
| +
|
| +/**
|
| + * @param {!importer.DefaultScanResult} scan
|
| + * @param {!Array<!FileEntry>} entries
|
| + * @return {!Promise} Resolves when scanning is finished.
|
| + * @private
|
| + */
|
| +importer.DefaultMediaScanner.prototype.scanMediaFiles_ =
|
| + function(scan, entries) {
|
| + var handleFileEntry = this.onFileEntryFound_.bind(this, scan);
|
| +
|
| + /**
|
| + * @param {number} begin The beginning offset in the list of entries
|
| + * to process.
|
| + * @return {!Promise}
|
| + */
|
| + var scanChunk = function(begin) {
|
| + // the second arg to slice is an exclusive end index, so we +1 batch size.
|
| + var end = begin + importer.DefaultMediaScanner.SCAN_BATCH_SIZE + 1;
|
| + return Promise.all(
|
| + entries.slice(begin, end).map(handleFileEntry))
|
| + .then(
|
| + function() {
|
| + if (end < entries.length) {
|
| + return scanChunk(end);
|
| + }
|
| + });
|
| + };
|
| +
|
| + return scanChunk(0);
|
| +};
|
| +
|
| /**
|
| * Notifies all listeners at some point in the near future.
|
| *
|
| @@ -136,55 +204,21 @@ importer.DefaultMediaScanner.prototype.notify_ = function(event, result) {
|
| };
|
|
|
| /**
|
| - * Resolves the entry by either:
|
| - * a) recursing on it (when a directory)
|
| - * b) adding it to the results (when a media type file)
|
| - * c) ignoring it, if neither a or b
|
| - *
|
| - * @param {!importer.DefaultScanResult} scan
|
| - * @param {!importer.DirectoryWatcher} watcher
|
| - * @param {!Entry} entry
|
| - *
|
| - * @return {!Promise}
|
| - * @private
|
| - */
|
| -importer.DefaultMediaScanner.prototype.scanEntry_ =
|
| - function(scan, watcher, entry) {
|
| -
|
| - if (entry.isDirectory) {
|
| - return this.scanDirectory_(
|
| - scan,
|
| - watcher,
|
| - /** @type {!DirectoryEntry} */ (entry));
|
| - }
|
| -
|
| - // Since this entry is by client code (and presumably the user)
|
| - // we add it directly (skipping over the history dupe check).
|
| - return this.onUniqueFileFound_(scan, /** @type {!FileEntry} */ (entry));
|
| -};
|
| -
|
| -/**
|
| - * Finds all files beneath directory.
|
| + * Finds all files media files beneath directory AND adds directory
|
| + * watchers for each encountered directory.
|
| *
|
| - * @param {!importer.DefaultScanResult} scan
|
| + * @param {!DirectoryEntry} directory
|
| * @param {!importer.DirectoryWatcher} watcher
|
| - * @param {!DirectoryEntry} entry
|
| - * @return {!Promise}
|
| + * @return {!Promise<!Array<!FileEntry>>}
|
| * @private
|
| */
|
| -importer.DefaultMediaScanner.prototype.scanDirectory_ =
|
| - function(scan, watcher, entry) {
|
| - // Collect promises for all files being added to results.
|
| - // The directory scan promise can't resolve until all
|
| - // file entries are completely promised.
|
| - var promises = [];
|
| +importer.DefaultMediaScanner.prototype.crawlDirectory_ =
|
| + function(directory, watcher) {
|
| + var mediaFiles = [];
|
|
|
| return fileOperationUtil.findEntriesRecursively(
|
| - entry,
|
| - /**
|
| - * @param {!Entry} entry
|
| - * @this {importer.DefaultMediaScanner}
|
| - */
|
| + directory,
|
| + /** @param {!Entry} entry */
|
| function(entry) {
|
| if (watcher.triggered) {
|
| return;
|
| @@ -195,14 +229,14 @@ importer.DefaultMediaScanner.prototype.scanDirectory_ =
|
| // function findEntriesRecursively does that. So we
|
| // just watch the directory for modifications, and that's it.
|
| watcher.addDirectory(/** @type {!DirectoryEntry} */(entry));
|
| - return;
|
| + } else if (importer.isEligibleType(entry)) {
|
| + mediaFiles.push(/** @type {!FileEntry} */ (entry));
|
| }
|
| -
|
| - promises.push(
|
| - this.onFileEntryFound_(scan, /** @type {!FileEntry} */(entry)));
|
| -
|
| - }.bind(this))
|
| - .then(Promise.all.bind(Promise, promises));
|
| + })
|
| + .then(
|
| + function() {
|
| + return mediaFiles;
|
| + });
|
| };
|
|
|
| /**
|
| @@ -343,7 +377,7 @@ importer.DefaultScanResult = function(hashGenerator) {
|
|
|
| /**
|
| * List of file entries found while scanning.
|
| - * @private {!Array.<!FileEntry>}
|
| + * @private {!Array<!FileEntry>}
|
| */
|
| this.fileEntries_ = [];
|
|
|
|
|