-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Downloading videos using Background Fetch API #169
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's my first pass.
Thanks @dero for working on it!
src/js/classes/BackgroundFetch.js
Outdated
this.id, | ||
urls, | ||
{ | ||
title: videoData.title, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
videoData.title
may end up being confusing. See video at http://localhost:5000/multiple-sources/ for instance.
Shall we have something like Downloading "${videoData.title}" video
? (Source)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 7979e32.
src/js/classes/BackgroundFetch.js
Outdated
|
||
// eslint-disable-next-line compat/compat | ||
navigator.serviceWorker.ready.then(async (swReg) => { | ||
this.maybeAbort(swReg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you'd want to await there before or is this intentional?
this.maybeAbort(swReg); | |
await this.maybeAbort(swReg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 7979e32.
src/js/sw/sw.js
Outdated
@@ -217,3 +220,53 @@ const fetchHandler = async (event) => { | |||
self.addEventListener('install', precacheAssets); | |||
self.addEventListener('activate', clearOldCaches); | |||
self.addEventListener('fetch', fetchHandler); | |||
|
|||
/** @type {MessagePort} */ | |||
let messageChannelPort; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some quick comment to explain where it comes from may be helpful to readers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 7979e32.
src/js/sw/sw.js
Outdated
const bgFetchHandler = async (e) => { | ||
/** @type {BackgroundFetchRegistration} */ | ||
const bgFetchRegistration = e.registration; | ||
const bgFetch = new BackgroundFetch(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Shall we move this until we actually need videoId
?
const bgFetchHandler = async (e) => {
/** @type {BackgroundFetchRegistration} */
const bgFetchRegistration = e.registration;
const records = await bgFetchRegistration.matchAll();
const urls = records.map((record) => record.request.url);
if (urls.length === 0)
return;
const responsePromises = records.map((record) => record.responseReady);
const responses = await Promise.all(responsePromises);
const bgFetch = new BackgroundFetch();
bgFetch.fromRegistration(bgFetchRegistration);
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@beaufortfrancois Good suggestion, thanks! Addressed in 7979e32.
@@ -217,3 +220,53 @@ const fetchHandler = async (event) => { | |||
self.addEventListener('install', precacheAssets); | |||
self.addEventListener('activate', clearOldCaches); | |||
self.addEventListener('fetch', fetchHandler); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we gate all the code added only if (!('BackgroundFetchManager' in self))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@beaufortfrancois Thank you, addressed in 7979e32.
LGTM. Thanks @dero! |
|
Why the revert? |
Short Screencast
kino-background-fetch-api.mp4
Summary
This PR adds support for downloading single videos and streamed videos using Background Fetch API.
We're adding an
offline
version of MPEG DASH manifests to all streamed videos. Thisoffline
manifest only contains one selected video and audio representation (HD H.264 MP4), which allows us to only download this one representation for offline playback.We've been doing this on-the-fly in the past, but with the introduction of Background Fetch API, it arguably make more sense to move towards using the more explicit separate offline manifests, because it would bring a larger amount of complexity to the codebase if we tried to manipulate DASH manifest data on the fly in the service worker.
DOMParser
object is not available in the worker context, meaning that parsing the manifest file would have to be done by an external library like xmldom. (Extra bundle weight, one more thing to maintain and rely on.)video
element or use itscanPlayType
method statically from the worker context. That means we can't test which of the representations in the manifest are actually playable on the current device and in the current browser. We would need to build a cache layer in IDB in order to figure that out ahead of time and cache it for later when SW is invoked with the downloaded files.We can avoid both issues by uploading the offline version of each manifest upfront. Plus this approach allows us to simplify the code quite a bit.
The main downside, I think, is that users will not be able to select their preferred download resolution with static offline manifests in place. Note: This is not a regression, we never had a setting for download quality. But this change does not allow for such a setting should we decide to implement it in the future.
Edit: Thinking about this a bit more, maybe it would be possible to leverage the Media Capabilities API to detect support and gain playback performance estimates for individual resources listed in DASH manifests – the API should be available from worker threads.
We might decide to pick this back up later.
Questions
Fixes #25