Использование файловой системы в качестве источника видео для воспроизведения в автономном режиме

Я пытаюсь добавить автономные функции в свой видеоплеер HTML5. Я пытаюсь записать файлы в файловую систему chrome в виде большого двоичного объекта, а затем прочитать их оттуда. Я считаю, что столкнулся с проблемой, когда файлы на самом деле не записываются, а только имя файла. Поскольку мой приведенный ниже код в настоящее время составлен, он работает, хотя и только в том случае, если он постоянно подключен к Интернету. Моя цель - загрузить файлы в постоянный каталог в файловой системе, а затем продолжить воспроизведение, если Интернет отключен.

$(document).ready(function() {


    var dir = "http://www.kevmoe.com/networks/gsplayer/";
    var fileextension = ".mp4";
    var srcfiles = $.ajax({
        //This will retrieve the contents of the folder if the folder is configured as 'browsable'
        url: dir,
        success: function(data) {
            //List all .mp4 file names in the page
            $(data).find("a:contains(" + fileextension + ")").each(function() {
                var filename = $(this).attr("href").replace(window.location.host, "").replace("http://", "");

                $("#container").append("<div id='div1' class='video'><video id='video1' class='vidarray' preload='none' poster='bkg.png'><source src='" + filename + "' type='video/mp4'></video></div>");
                async: false;


                window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

                window.requestFileSystem(window.PERSISTANT, 200000 * 1024 * 1024, initFS, errorHandler);

                function initFS(fs) {
                    console.log('filesystem engaged'); // Just to check if everything is OK :)
                    // place the functions you will learn bellow here
                    function errorHandler(err) {
                        var msg = 'An error occured: ';
                    };

                    function createDir(rootDir, folders) {
                        rootDir.getDirectory(folders[0], {
                            create: true
                        }, function(dirEntry) {
                            if (folders.length) {
                                createDir(dirEntry, folders.slice(1));
                            }
                        }, errorHandler);
                    };

                    createDir(fs.root, 'files/video/'.split('/'));

                    fs.root.getDirectory('video', {}, function(dirEntry) {
                        var dirReader = dirEntry.createReader();
                        dirReader.readEntries(function(entries) {
                            for (var i = 0; i < entries.length; i++) {
                                var entry = entries[i];
                                if (entry.isDirectory) {
                                    console.log('Directory: ' + entry.fullPath);
                                } else if (entry.isFile) {
                                    console.log('File: ' + entry.fullPath);
                                }
                            }

                        }, errorHandler);
                    }, errorHandler);

                    fs.root.getFile(filename, {
                        create: true,
                        exclusive: true
                    }, function(fileEntry) {
                        fileEntry.createWriter(function(fileWriter) {
                            var blob = new Blob([data], {
                                type: 'video/mp4'
                            });
                            fileWriter.write(blob);
                        }, errorHandler);

                        console.log('file downloaded');
                    }, errorHandler);

                    //Try to add an event listener for when all files are finished loading into file system. Then use another function to source the videos locally.
                    var dirReader = fs.root.createReader();
                    var entries = [];

                    // Call the reader.readEntries() until no more results are returned.

                    dirReader.readEntries(function(results) {

                        //List all .mp4 file names in the page
                        $(results).find("a:contains(" + fileextension + ")").each(function() {
                            var filename = $(this).attr("href").replace(window.location.host, "").replace("http://", "");

                            $("#container").append("<div id='div1' class='video'><video id='video1' class='vidarray' preload='none' poster='bkg.png'><source src='" + filename + "' type='video/mp4'></video></div>");
                            async: false;

                        }, errorHandler);
                    });
                };

                function errorHandler() {
                    console.log('An error occured');
                };
            });


            var videos = $('.video');
            //handle ending of video
            videos.find('video').on('ended', function() {
                playNextVideo(videos);
            });

            // start with the first one
            playNextVideo(videos);


            function playNextVideo(videoList) {
                var activeVideo = videoList.filter('.active').removeClass('active'), // identify active video and remove active class
                    activeIndex = videoList.index(activeVideo), // get the active video index in the group
                    nextVideo = videoList.eq(activeIndex + 1), // get the next video in line
                    actualVideo;

                // if there is no next video start from first
                if (nextVideo.length == 0) nextVideo = videoList.first();

                // pause all videos
                videoList.find('video').each(function() {
                    this.pause();
                })

                // get reference to next video element
                actualVideo = nextVideo.find('video').get(0);

                // add active class to next video
                nextVideo.addClass('active');

                // load and play
                actualVideo.volume = 0.04;
                actualVideo.load();
                actualVideo.play();
            }
        }
    });
});

person KevMoe    schedule 30.06.2017    source источник
comment
Решит ли вашу проблему локальное кэширование видео в браузере, или вы настаиваете на том, чтобы оно было загружено в определенный каталог для использования в автономном режиме? Если вам просто нужно иметь возможность воспроизводить видео в автономном режиме, этот вопрос о переполнении стека может быть помощи вам.   -  person Christopher Bradshaw    schedule 05.07.2017
comment
Это может быть просто опечатка, но window.PERSISTANT не определено, а window.PERSISTENT равно 1. Если это не так (опечатка), то вы, вероятно, записываете во ВРЕМЕННОЕ хранилище вместо ПОСТОЯННОГО.   -  person IronGeek    schedule 06.07.2017
comment
Кристофер. Я пытался кэшировать, но это не сработало для больших файлов.   -  person KevMoe    schedule 06.07.2017
comment
IronGreek, это была опечатка, спасибо... хотя исправление не решило общей проблемы.   -  person KevMoe    schedule 07.07.2017


Ответы (2)


Протокол filesystem: хранит файлы со ссылкой на то же происхождение, что и document, который запрашивает LocalFileSystem. То есть, если JavaScript at Question создан, например, по адресу http://example.org, путь к LocalFileSystem должен иметь тот же источник, что и http://example.org, а не протокол file:.

Если вы пытаетесь сохранить файлы или папки для доступа по протоколу file: в автономном режиме, вы можете создать документ .html для использования в качестве закладки шаблона.

Посетите локальный файл .html один раз, находясь в сети, чтобы получить файлы и заполнить LocalFileSystem. Если navigator.onLine равно true, перейдите к http://example.org, в противном случае получите и обработайте файлы и папки, хранящиеся в LocalFileSystem.

Создайте список как JSON или JavaScript Array, чтобы хранить список файлов для извлечения, вместо того, чтобы анализировать .html document для определения расположения файлов.

Сохраните локальный файл в качестве закладки. Запустите Chromium, Chrome с установленным флагом --allow-file-access-from-files для доступа к протоколу filesystem: из протокола file: и протоколу file: по протоколу filesystem:, если он не в сети.

<!DOCTYPE html>
<html>
<head>
  <title>LocalFileSystem Offline Videos Bookmark</title>
</head>
<body>
<script>

// location to visit if online
const onLineURL = "https://lorempixel.com/" 
                  + window.innerWidth 
                  + "/" 
                  + window.innerHeight + "/cats";

const props = {
  requestedBytes: 1024 * 1024 * 20000,
  folder: "videos",
  // list of files to fetch for offline viewing
  mediaList: [
    "http://mirrors.creativecommons.org/movingimages/webm/"
    + "ScienceCommonsJesseDylan_240p.webm"
  , "https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4"
  ]
};

let grantedBytes = 0;

function getLocalFileSystem ({requestedBytes = 0, mediaList=[], folder = ""}) {
    if (!requestedBytes || !mediaList.length || !folder) {
      throw new Error("requestedBytes: Number"
                     + " or mediaList: Array"
                     + " or folder: String not defined");
    };
    // do stuff with `filesystem:` URL
    function processLocalFilePath(localPath) {
        const video = document.createElement("video");
        document.body.appendChild(video);
        video.controls = true;
        video.src = localPath;
    }

    function errorHandler(err) {
        console.log(err);
    }

    function writeFile(dir, fn, fp, localPath) {
        console.log(dir, fn, fp, localPath);
        dir.getFile(fn, {}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                fileWriter.onwriteend = function(e) {
                    // do stuff when file is written
                    console.log(e.type, localPath + " written");
                    window.webkitResolveLocalFileSystemURL(localPath
                    , function(file) {
                        // file exists in LocalFileSystem
                        processLocalFilePath(localPath);
                    }, errorHandler)
                };

                fileWriter.onerror = errorHandler;
                fetch(fp).then(function(response) {
                    return response.blob()
                }).then(function(blob) {
                    fileWriter.write(blob);
                }).catch(errorHandler)
            }, errorHandler);
        }, errorHandler);
    }

    if (mediaList && mediaList.length) {
        navigator.webkitTemporaryStorage.requestQuota(requestedBytes
        , function(grantedBytes_) {
            grantedBytes = grantedBytes_;
            console.log("Requested bytes:", requestedBytes
                       , "Granted bytes:", grantedBytes);
            window.webkitRequestFileSystem(window.TEMPORARY
            , grantedBytes
            , function(fs) {

                const url = fs.root.toURL();

                mediaList.forEach(function(filename) {

                    const localPath = url + folder + "/" 
                                      + filename.split("/").pop();

                    window.webkitResolveLocalFileSystemURL(localPath
                    , function(file) {
                        // file exists in LocalFileSystem
                        console.log(localPath + " exists at LocalFileSystem");
                        processLocalFilePath(localPath)

                    }, function(err) {
                        console.log(err, localPath 
                        + " not found in LocalFileSystem");
                        // Exception is thrown if file 
                        // or folder path not found
                        // create `folder` directory, get files
                        fs.root.getDirectory(folder, {}
                        , function(dir) {
                            writeFile(dir
                            , filename.split("/").pop()
                            , filename
                            , localPath);
                        }),
                        errorHandler
                    })
                })

            })
        }, errorHandler)
    }
}

if (location.href !== onLineURL && navigator.onLine) {
    location.href = onLineURL;
} else {
    getLocalFileSystem(props);
}

</script>
</body>
</html>

Смотрите также


Альтернативным подходом может быть использование ServiceWorker

person guest271314    schedule 10.07.2017

Ваш пользователь должен предоставить вашему приложению разрешение на локальное хранение данных, прежде чем ваше приложение сможет использовать постоянное хранилище. Вот почему вы должны сначала запросить квоту. Количество байтов, которое вы запрашиваете, составляет 200000 * 1024 * 1024 байта.

window.storageInfo.requestQuota(PERSISTENT, 200000 * 1024 * 1024, 
    function(grantedBytes) {
        window.requestFileSystem(window.PERSISTENT, grantedBytes, onInitFs, errorHandler);
    }, 
    errorHandler
);

документация MDN

Я заметил, что вы пишете это для Chrome, вот как вы управляете квотой в Chrome

person jpuntd    schedule 09.07.2017