2017-01-29 6 views
4

すべての静的リソースをキャッシュするオフラインアプリがあります。現在、ビデオアセットの最初の15秒のみがキャッシュされています。オフラインで使用するためにService Worker APIを使用してHTML5ビデオ全体をキャッシュすることはできますか?

以下は、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

多分あなたはブロブにビデオを変換し、ブロブを保存することができます。 [this](https://simpl.info/video/offline/)にはいくつかの関連するテクニックがあるようです。 – danyamachine

+0

キャッシュAPIサービスワーカーは[ストア要求/応答のペア]を使用します(https://developer.mozilla.org/en-US/docs/Web/API/Cache/put#パラメータ)。したがって、ファイルタイプの制限があるかどうかは疑問です。 [引用:](https://developer.mozilla.org/en-US/docs/Web/API/Cache) '...キャッシュされているリクエスト/レスポンスオブジェクトのペアのための記憶機構...' –

+1

実際、私はそれをテストに入れました。それは期待通りにうまくいきます。 [こちらをチェックしてください](https://lazysheepherd.com/sw-test/offline/) –

答えて

3

に私が最初に全体のビデオ(複数可)を見ずに、最初のページのロードのオフラインのビデオを達成するために、次の手順を使用していました。

  1. サービスワーカーを登録し、すべての要求をキャッシュします。この場合、静的資産は'/'になります。サービスワーカーのfetchイベントを調べると、後続のリクエストもキャッシュされていることがわかります。
  2. fetch APIを使用して、ビデオをblobとしてリクエストします。

    const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob()); 
    videoRequest.then(blob => { 
        ... 
    }); 
    
    ブロブとしてビデオを要求するフェッチ使用

  • blobを格納するIndexedDB APIを使用します。 (保存中にメインスレッドをブロックしないように、LocalStorageの代わりにIndexedDBを使用してください)
  • これだけです!オフラインモードでは、サービスワーカーは要求を傍受し、htmlblobの両方をキャッシュから処理します。

    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> 
    

    サービスワーカー

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

    資源:

    関連する問題