简体   繁体   English

是否可以使用Service Worker API缓存整个HTML5视频以供离线使用?

[英]Is it possible to cache an entire HTML5 video using the Service Worker API for offline use?

I have an offline app that caches all static resources. 我有一个缓存所有静态资源的离线应用程序。 Currently, only the first 15 seconds of video assets are cached. 目前,只缓存前15秒的视频资产。

Below shows basic implementations of the install and fetch event listeners. 下面显示了installfetch事件侦听器的基本实现。

Service Worker: 服务人员:

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);
    });
  );
});

And in index.html index.html

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

I used the following steps to accomplish offline video on the first page load without first watching the entire video(s). 我使用以下步骤在第一页加载时完成离线视频,而不先观看整个视频。

  1. Register a service worker and cache all requests. 注册服务工作者并缓存所有请求。 Static assets are just '/' for this case. 对于这种情况,静态资产只是'/' If you inspect the service worker's fetch event, you'll see that subsequent requests are also cached. 如果检查服务工作者的fetch事件,您将看到后续请求也被缓存。
  2. Use the fetch API to request a video as a blob . 使用fetch API将视频作为blob请求。

Example using fetch to request a video as a blob 使用fetch将视频作为blob请求的示例

const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob());
videoRequest.then(blob => {
  ...
});
  1. Use the IndexedDB API to store the blob . 使用IndexedDB API存储blob (Use IndexedDB instead of LocalStorage to avoid blocking the main thread while storing.) (使用IndexedDB而不是LocalStorage来避免在存储时阻塞主线程。)

That's it! 而已! Now when in offline mode, the service worker will intercept requests and serve both the html and blob from cache. 现在,当处于脱机模式时,服务工作者将拦截请求并从缓存中提供htmlblob

index.html 的index.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>

Service Worker 服务人员

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)
        })
      );
    })
  );
});

Resources: 资源:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM