[英]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. 下面显示了
install
和fetch
事件侦听器的基本实现。
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). 我使用以下步骤在第一页加载时完成离线视频,而不先观看整个视频。
'/'
for this case. '/'
。 If you inspect the service worker's fetch
event, you'll see that subsequent requests are also cached. fetch
事件,您将看到后续请求也被缓存。 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 => {
...
});
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. 现在,当处于脱机模式时,服务工作者将拦截请求并从缓存中提供
html
和blob
。
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.