[WIP] Fix bug loading movies
This was a fun journey! Turns out Next 12 is using a new faster JS compiler called SWC, which had a compiler bug that triggered here! The incorrect looping behavior caused `libraryUrl` to sometimes be `null` by the time the movie promise completes, because `layer` was set to whatever the `last` layer in the list had been. https://github.com/swc-project/swc/issues/2624 Anyway, turns out this code has been through a few refactors, and the `async` function wrapper is extraneous now! So I've just deleted it and inlined its code. Ta da! lol
This commit is contained in:
parent
4af2719098
commit
7fd85e5e2a
1 changed files with 66 additions and 70 deletions
|
@ -388,83 +388,79 @@ export function usePreloadLayers(layers) {
|
||||||
setError(null);
|
setError(null);
|
||||||
setLayersHaveAnimations(false);
|
setLayersHaveAnimations(false);
|
||||||
|
|
||||||
const loadAssets = async () => {
|
const minimalAssetPromises = [];
|
||||||
const minimalAssetPromises = [];
|
const imageAssetPromises = [];
|
||||||
const imageAssetPromises = [];
|
const movieAssetPromises = [];
|
||||||
const movieAssetPromises = [];
|
for (const layer of layers) {
|
||||||
for (const layer of layers) {
|
const imageAssetPromise = loadImage(
|
||||||
const imageAssetPromise = loadImage(
|
getBestImageUrlForLayer(layer, { hiResMode })
|
||||||
getBestImageUrlForLayer(layer, { hiResMode })
|
);
|
||||||
|
imageAssetPromises.push(imageAssetPromise);
|
||||||
|
|
||||||
|
if (layer.canvasMovieLibraryUrl) {
|
||||||
|
// Start preloading the movie. But we won't block on it! The blocking
|
||||||
|
// request will still be the image, which we'll show as a
|
||||||
|
// placeholder, which should usually be noticeably faster!
|
||||||
|
const movieLibraryPromise = loadMovieLibrary(
|
||||||
|
layer.canvasMovieLibraryUrl
|
||||||
);
|
);
|
||||||
imageAssetPromises.push(imageAssetPromise);
|
const movieAssetPromise = movieLibraryPromise.then((library) => ({
|
||||||
|
library,
|
||||||
|
libraryUrl: layer.canvasMovieLibraryUrl,
|
||||||
|
}));
|
||||||
|
movieAssetPromise.libraryUrl = layer.canvasMovieLibraryUrl;
|
||||||
|
movieAssetPromise.cancel = () => movieLibraryPromise.cancel();
|
||||||
|
movieAssetPromises.push(movieAssetPromise);
|
||||||
|
|
||||||
if (layer.canvasMovieLibraryUrl) {
|
// The minimal asset for the movie case is *either* the image *or*
|
||||||
// Start preloading the movie. But we won't block on it! The blocking
|
// the movie, because we can start rendering when either is ready.
|
||||||
// request will still be the image, which we'll show as a
|
minimalAssetPromises.push(
|
||||||
// placeholder, which should usually be noticeably faster!
|
Promise.any([imageAssetPromise, movieAssetPromise])
|
||||||
const movieLibraryPromise = loadMovieLibrary(
|
);
|
||||||
layer.canvasMovieLibraryUrl
|
} else {
|
||||||
);
|
minimalAssetPromises.push(imageAssetPromise);
|
||||||
const movieAssetPromise = movieLibraryPromise.then((library) => ({
|
}
|
||||||
library,
|
}
|
||||||
libraryUrl: layer.canvasMovieLibraryUrl,
|
|
||||||
}));
|
|
||||||
movieAssetPromise.libraryUrl = layer.canvasMovieLibraryUrl;
|
|
||||||
movieAssetPromise.cancel = () => movieLibraryPromise.cancel();
|
|
||||||
movieAssetPromises.push(movieAssetPromise);
|
|
||||||
|
|
||||||
// The minimal asset for the movie case is *either* the image *or*
|
// When the minimal assets have loaded, we can say the layers have
|
||||||
// the movie, because we can start rendering when either is ready.
|
// loaded, and allow the UI to start showing them!
|
||||||
minimalAssetPromises.push(
|
Promise.all(minimalAssetPromises)
|
||||||
Promise.any([imageAssetPromise, movieAssetPromise])
|
.then(() => {
|
||||||
);
|
if (canceled) return;
|
||||||
} else {
|
setLoadedLayers(layers);
|
||||||
minimalAssetPromises.push(imageAssetPromise);
|
})
|
||||||
}
|
.catch((e) => {
|
||||||
|
if (canceled) return;
|
||||||
|
console.error("Error preloading outfit layers", e);
|
||||||
|
setError(e);
|
||||||
|
|
||||||
|
// Cancel any remaining promises, if cancelable.
|
||||||
|
imageAssetPromises.forEach((p) => p.cancel && p.cancel());
|
||||||
|
movieAssetPromises.forEach((p) => p.cancel && p.cancel());
|
||||||
|
});
|
||||||
|
|
||||||
|
// As the movie assets come in, check them for animations, to decide
|
||||||
|
// whether to show the Play/Pause button.
|
||||||
|
const checkHasAnimations = (asset) => {
|
||||||
|
if (canceled) return;
|
||||||
|
let assetHasAnimations;
|
||||||
|
try {
|
||||||
|
assetHasAnimations = getHasAnimationsForMovieAsset(asset);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error testing layers for animations", e);
|
||||||
|
setError(e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the minimal assets have loaded, we can say the layers have
|
setLayersHaveAnimations(
|
||||||
// loaded, and allow the UI to start showing them!
|
(alreadyHasAnimations) => alreadyHasAnimations || assetHasAnimations
|
||||||
Promise.all(minimalAssetPromises)
|
|
||||||
.then(() => {
|
|
||||||
if (canceled) return;
|
|
||||||
setLoadedLayers(layers);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
if (canceled) return;
|
|
||||||
console.error("Error preloading outfit layers", e);
|
|
||||||
setError(e);
|
|
||||||
|
|
||||||
// Cancel any remaining promises, if cancelable.
|
|
||||||
imageAssetPromises.forEach((p) => p.cancel && p.cancel());
|
|
||||||
movieAssetPromises.forEach((p) => p.cancel && p.cancel());
|
|
||||||
});
|
|
||||||
|
|
||||||
// As the movie assets come in, check them for animations, to decide
|
|
||||||
// whether to show the Play/Pause button.
|
|
||||||
const checkHasAnimations = (asset) => {
|
|
||||||
if (canceled) return;
|
|
||||||
let assetHasAnimations;
|
|
||||||
try {
|
|
||||||
assetHasAnimations = getHasAnimationsForMovieAsset(asset);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error testing layers for animations", e);
|
|
||||||
setError(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLayersHaveAnimations(
|
|
||||||
(alreadyHasAnimations) => alreadyHasAnimations || assetHasAnimations
|
|
||||||
);
|
|
||||||
};
|
|
||||||
movieAssetPromises.forEach((p) =>
|
|
||||||
p.then(checkHasAnimations).catch((e) => {
|
|
||||||
console.error(`Error preloading movie library ${p.libraryUrl}:`, e);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
movieAssetPromises.forEach((p) =>
|
||||||
loadAssets();
|
p.then(checkHasAnimations).catch((e) => {
|
||||||
|
console.error(`Error preloading movie library ${p.libraryUrl}:`, e);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
|
Loading…
Reference in a new issue