# Source: offline/controllers/OfflineController.js

    /**
     * The copyright in this software is being made available under the BSD License,
     * included below. This software may be subject to other third party and contributor
     * rights, including patent rights, and no such rights are granted under this license.
     *
     * Copyright (c) 2013, Dash Industry Forum.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *  * Redistributions of source code must retain the above copyright notice, this
     *  list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *  this list of conditions and the following disclaimer in the documentation and/or
     *  other materials provided with the distribution.
     *  * Neither the name of Dash Industry Forum nor the names of its
     *  contributors may be used to endorse or promote products derived from this software
     *  without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
     *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     *  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     *  POSSIBILITY OF SUCH DAMAGE.
     */

    import OfflineConstants from '../constants/OfflineConstants';
    import OfflineStoreController from './OfflineStoreController';
    import OfflineDownload from '../OfflineDownload';
    import IndexDBOfflineLoader from '../net/IndexDBOfflineLoader';
    import OfflineUrlUtils from '../utils/OfflineUrlUtils';
    import OfflineEvents from '../events/OfflineEvents';
    import OfflineErrors from '../errors/OfflineErrors';
    import OfflineRecord from '../vo/OfflineDownloadVo';

    /**
     * @module OfflineController
     * @param {Object} config - dependencies
     * @description Provides access to offline stream recording and playback functionality. This module can be accessed using the MediaPlayer API getOfflineController()
     */
    function OfflineController(config) {

        const context = this.context;
        const errHandler = config.errHandler;
        const events = config.events;
        const errors = config.errors;
        const settings = config.settings;
        const eventBus = config.eventBus;
        const debug = config.debug;
        const manifestLoader = config.manifestLoader;
        const manifestModel = config.manifestModel;
        const mediaPlayerModel = config.mediaPlayerModel;
        const abrController = config.abrController;
        const playbackController = config.playbackController;
        const dashMetrics = config.dashMetrics;
        const timelineConverter = config.timelineConverter;
        const segmentBaseController = config.segmentBaseController;
        const adapter = config.adapter;
        const manifestUpdater = config.manifestUpdater;
        const baseURLController = config.baseURLController;
        const schemeLoaderFactory = config.schemeLoaderFactory;
        const constants = config.constants;
        const dashConstants = config.dashConstants;
        const urlUtils = config.urlUtils;

        let instance,
            downloads,
            logger,
            offlineStoreController,
            offlineUrlUtils;

        function setup() {
            logger = debug.getLogger(instance);
            offlineStoreController = OfflineStoreController(context).create({
                eventBus: config.eventBus,
                errHandler: errHandler
            });
            offlineUrlUtils = OfflineUrlUtils(context).getInstance();
            urlUtils.registerUrlRegex(offlineUrlUtils.getRegex(), offlineUrlUtils);
            schemeLoaderFactory.registerLoader(OfflineConstants.OFFLINE_SCHEME, IndexDBOfflineLoader);

            downloads = [];
        }

        /*
        ---------------------------------------------------------------------------
            DOWNLOAD LIST FUNCTIONS
        ---------------------------------------------------------------------------
        */
        function getDownloadFromId(id) {
            let download = downloads.find((item) => {
                return item.getId() === id;
            });
            return download;
        }

        function createDownloadFromId(id) {
            let download;
            download = getDownloadFromId(id);

            if (!download) {
                // create download controller
                download = OfflineDownload(context).create({
                    id: id,
                    eventBus: eventBus,
                    events: events,
                    errors: errors,
                    settings: settings,
                    manifestLoader: manifestLoader,
                    manifestModel: manifestModel,
                    mediaPlayerModel: mediaPlayerModel,
                    manifestUpdater: manifestUpdater,
                    baseURLController: baseURLController,
                    abrController: abrController,
                    playbackController: playbackController,
                    adapter: adapter,
                    dashMetrics: dashMetrics,
                    timelineConverter: timelineConverter,
                    errHandler: errHandler,
                    segmentBaseController: segmentBaseController,
                    offlineStoreController: offlineStoreController,
                    debug: debug,
                    constants: constants,
                    dashConstants: dashConstants,
                    urlUtils: urlUtils
                });

                downloads.push(download);
            }

            return download;
        }

        function createDownloadFromStorage(offline) {
            let download = getDownloadFromId(offline.manifestId);

            if (!download) {
                download = createDownloadFromId(offline.manifestId);
                let status = offline.status;
                if (status === OfflineConstants.OFFLINE_STATUS_STARTED) {
                    status = OfflineConstants.OFFLINE_STATUS_STOPPED;
                }

                download.setInitialState({
                    url: offline.url,
                    progress: offline.progress,
                    originalUrl: offline.originalURL,
                    status: status
                });
            }

            return download;
        }

        function removeDownloadFromId(id) {
            return new Promise(function (resolve, reject) {
                let download = getDownloadFromId(id);
                let waitForStatusChanged = false;
                if (download) {
                    //is download running?
                    if (download.isDownloading()) {
                        //register status changed event
                        waitForStatusChanged = true;
                        const downloadStopped = function () {
                            eventBus.off(events.OFFLINE_RECORD_STOPPED, downloadStopped, instance);
                            return offlineStoreController.deleteDownloadById(id).then(function () {
                                resolve();
                            }).catch(function (err) {
                                reject(err);
                            });
                        };
                        eventBus.on(events.OFFLINE_RECORD_STOPPED, downloadStopped, instance);
                    }
                    download.deleteDownload();
                    let index = downloads.indexOf(download);
                    downloads.splice(index, 1);
                }

                if (!waitForStatusChanged) {
                    resolve();
                }
            });
        }

        function generateManifestId() {
            let timestamp = new Date().getTime();
            return timestamp;
        }

        /*
        ---------------------------------------------------------------------------

            OFFLINE CONTROLLER API

        ---------------------------------------------------------------------------
        */

        /**
         * Loads records from storage
         * This methods has to be called first, to be sure that all downloads have been loaded
         *
         * @return {Promise} asynchronously resolved
         * @memberof module:OfflineController
         */
        function loadRecordsFromStorage() {
            return new Promise(function (resolve, reject) {
                offlineStoreController.getAllManifests().then((items) => {
                    items.manifests.forEach((offline) => {
                        createDownloadFromStorage(offline);
                    });

                    resolve();
                }).catch((e) => {
                    logger.error('Failed to load downloads ' + e);
                    reject(e);
                });
            });
        }

        /**
         * Get all records from storage
         *
         * @return {Promise} asynchronously resolved with records
         * @memberof module:OfflineController
         * @instance
         */
        function getAllRecords() {
            let records = [];
            downloads.forEach((download) => {
                const record = new OfflineRecord();
                record.id = download.getId();
                record.progress = download.getDownloadProgression();
                record.url = download.getOfflineUrl();
                record.originalUrl = download.getManifestUrl();
                record.status = download.getStatus();
                records.push(record);
            });
            return records;
        }

        /**
         * Create a new content record in storage and download manifest from url
         *
         * @param {string} manifestURL - the content manifest url
         * @return {Promise} asynchronously resolved with record identifier
         * @memberof module:OfflineController
         * @instance
         */
        function createRecord(manifestURL) {
            return new Promise(function (resolve, reject) {
                let id = generateManifestId();

                // create download controller
                let download = createDownloadFromId(id);

                download.downloadFromUrl(manifestURL).then(() => {
                    download.initDownload();
                    resolve(id);
                })
                    .catch((e) => {
                        logger.error('Failed to download ' + e);
                        removeDownloadFromId(id).then(function () {
                            reject(e);
                        });
                    });
            });
        }

        /**
         * Start downloading the record with selected tracks representations
         *
         * @param {string} id - record identifier
         * @param {MediaInfo[]} mediaInfos - the selected tracks representations
         * @memberof module:OfflineController
         * @instance
         */
        function startRecord(id, mediaInfos) {
            let download = getDownloadFromId(id);
            if (download) {
                download.startDownload(mediaInfos);
            }
        }

        /**
         * Stop downloading of the record
         *
         * @param {string} id - record identifier
         * @memberof module:OfflineController
         * @instance
         */
        function stopRecord(id) {
            let download = getDownloadFromId(id);
            if (download) {
                download.stopDownload();
            }
        }

        /**
         * Resume downloading of the record
         *
         * @param {string} id - record identifier
         * @memberof module:OfflineController
         * @instance
         */
        function resumeRecord(id) {
            let download = getDownloadFromId(id);
            if (download) {
                download.resumeDownload();
            }
        }

        /**
         * Deletes a record from storage
         *
         * @param {string} id - record identifier
         * @memberof module:OfflineController
         * @instance
         */
        function deleteRecord(id) {
            return removeDownloadFromId(id).then(function () {
                return offlineStoreController.deleteDownloadById(id);
            });
        }

        /**
         * Get download progression of a record
         *
         * @param {string} id - record identifier
         * @return {number} percentage progression
         * @memberof module:OfflineController
         * @instance
         */
        function getRecordProgression(id) {
            let download = getDownloadFromId(id);
            if (download) {
                return download.getDownloadProgression();
            }
            return 0;
        }

        /**
         * Reset all records
         * @memberof module:OfflineController
         * @instance
         */
        function resetRecords() {
            downloads.forEach((download) => {
                download.resetDownload();
            });
        }

        /**
         * Reset
         * @instance
         */
        function reset() {
            resetRecords();
            schemeLoaderFactory.unregisterLoader(OfflineConstants.OFFLINE_SCHEME);
        }

        instance = {
            loadRecordsFromStorage: loadRecordsFromStorage,
            createRecord: createRecord,
            startRecord: startRecord,
            stopRecord: stopRecord,
            resumeRecord: resumeRecord,
            deleteRecord: deleteRecord,
            getRecordProgression: getRecordProgression,
            getAllRecords: getAllRecords,
            resetRecords: resetRecords,
            reset: reset
        };

        setup();

        return instance;
    }

    OfflineController.__dashjs_factory_name = 'OfflineController';
    const factory = dashjs.FactoryMaker.getClassFactory(OfflineController); /* jshint ignore:line */
    factory.events = OfflineEvents;
    factory.errors = OfflineErrors;
    dashjs.FactoryMaker.updateClassFactory(OfflineController.__dashjs_factory_name, factory); /* jshint ignore:line */
    export default factory;

#### Search results