Можно ли кэшировать все видео HTML5 с помощью API Service Worker для автономного использования?

у меня есть автономное приложение, которое кэширует все статические ресурсы. В настоящее время, кэшируются только первые 15 секунд видео активов.

ниже показаны основные реализации install и fetch прослушиватели событий.

Услуги Работник:

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('v1').then(cache => {
      return cache.addAll([
        '/',
        '/videos/one.mp4',
        '/videos/two.mp4'
      ]);
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      if (response) return response;
      return fetch(event.request);
    });
  );
});

и index.html

<video controls preload>
  <source src="/videos/one.mp4" type="video/mp4">
</video>

1 ответов


я использовал следующие шаги для выполнения автономного видео При загрузке первой страницы без предварительного просмотра всего видео(ов).

  1. зарегистрируйте работника службы и кэшируйте все запросы. Статические активы просто '/' для данного случая. Если вы проверяете fetch событие, вы увидите, что последующие запросы также будут кэшированы.
  2. использовать fetch API для запроса видео в качестве blob.

пример использования fetch to запросить видео в виде blob

const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob());
videoRequest.then(blob => {
  ...
});
  1. использовать IndexedDB API для хранения blob. (Используйте IndexedDB вместо LocalStorage чтобы избежать блокировки основного потока при хранении.)

вот именно! Теперь, когда в автономном режиме, работник службы будет перехватывать запросы и обслуживать оба html и blob из кэша.

.HTML-код

<!DOCTYPE html>
<html>
<head>
  <title>Test</title>
</head>
<body>

  <h1>Service Worker Test</h1>

  <p>Try reloading the page without an Internet connection.</p>

  <video controls></video>

  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js').then(registration => {
          console.log('ServiceWorker registration successful with scope: ', registration.scope);
        }).catch(error => {
          console.log('ServiceWorker registration failed: ', error);
        });
      });
    } else {
      alert('serviceWorker is not in navigator');
    }
  </script>

  <script>
    const videos = {
      one: document.querySelector('video')
    };

    const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob());
    videoRequest.then(blob => {
      const request = indexedDB.open('databaseNameHere', 1);

      request.onsuccess = event => {
        const db = event.target.result;

        const transaction = db.transaction(['videos']);
        const objectStore = transaction.objectStore('videos');

        const test = objectStore.get('test');

        test.onerror = event => {
          console.log('error');
        };

        test.onsuccess = event => {
          videos.one.src = window.URL.createObjectURL(test.result.blob);
        };
      }

      request.onupgradeneeded = event => {
        const db = event.target.result;
        const objectStore = db.createObjectStore('videos', { keyPath: 'name' });

        objectStore.transaction.oncomplete = event => {
          const videoObjectStore = db.transaction('videos', 'readwrite').objectStore('videos');
          videoObjectStore.add({name: 'test', blob: blob});
        };
      }
    });
  </script>
</body>
</html>

сервис Рабочий

const latest = {
  cache: 'some-cache-name/v1'
};

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(latest.cache).then(cache => {
      return cache.addAll([
        '/'
      ]);
    })
  );
});

self.addEventListener('fetch', event => {
  // exclude requests that start with chrome-extension://
  if (event.request.url.startsWith('chrome-extension://')) return;
  event.respondWith(
    caches.open(latest.cache).then(cache => {
      return cache.match(event.request).then(response => {
        var fetchPromise = fetch(event.request).then(networkResponse => {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        })
        return response || fetchPromise;
      })
    })
  );
});

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(cacheName => {
          if (cacheName === latest.cache) {
            return false;
          }

          return true;
        }).map(cacheName => {
          return caches.delete(cacheName)
        })
      );
    })
  );
});

ресурсы: