webamp/js/fileUtils.js
2018-03-15 22:51:46 -07:00

132 lines
3.7 KiB
JavaScript

import invariant from "invariant";
export function genMediaTags(file) {
invariant(
file != null,
"Attempted to get the tags of media file without passing a file"
);
// Workaround https://github.com/aadsm/jsmediatags/issues/83
if (typeof file === "string" && !/^[a-z]+:\/\//i.test(file)) {
file = `${location.protocol}//${location.host}${location.pathname}${file}`;
}
return new Promise((resolve, reject) => {
require.ensure(
["jsmediatags/dist/jsmediatags"],
require => {
const jsmediatags = require("jsmediatags/dist/jsmediatags");
try {
jsmediatags.read(file, { onSuccess: resolve, onError: reject });
} catch (e) {
// Possibly jsmediatags could not find a parser for this file?
// Nothing to do.
// Consider removing this after https://github.com/aadsm/jsmediatags/issues/83 is resolved.
reject(e);
}
},
() => {
// The dependency failed to load
},
"jsmediatags"
);
});
}
export function genMediaDuration(url) {
invariant(
typeof url === "string",
"Attempted to get the duration of media file without passing a url"
);
return new Promise((resolve, reject) => {
// TODO: Does this actually stop downloading the file once it's
// got the duration?
const audio = document.createElement("audio");
audio.crossOrigin = "anonymous";
const durationChange = () => {
resolve(audio.duration);
audio.removeEventListener("durationchange", durationChange);
audio.url = null;
// TODO: Not sure if this really gets cleaned up.
};
audio.addEventListener("durationchange", durationChange);
audio.addEventListener("error", e => {
reject(e);
});
audio.src = url;
});
}
export async function genArrayBufferFromFileReference(fileReference) {
invariant(
fileReference != null,
"Attempted to get an ArrayBuffer without assing a fileReference"
);
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(e) {
resolve(e.target.result);
};
reader.onerror = function(e) {
reject(e);
};
reader.readAsArrayBuffer(fileReference);
});
}
export async function genArrayBufferFromUrl(url) {
return new Promise((resolve, reject) => {
const oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = () => {
const arrayBuffer = oReq.response; // Note: not oReq.responseText
resolve(arrayBuffer);
};
oReq.onerror = reject;
oReq.send(null);
});
}
export async function promptForFileReferences({
accept = null,
directory = false
}) {
return new Promise(resolve => {
// Does this represent a memory leak somehow?
// Can this fail? Do we ever reject?
const fileInput = document.createElement("input");
if (accept) fileInput.setAttribute("accept", accept);
fileInput.type = "file";
fileInput.multiple = true;
fileInput.webkitdirectory = directory;
fileInput.directory = directory;
fileInput.mozdirectory = directory;
// Not entirely sure why this is needed, since the input
// was just created, but somehow this helps prevent change
// events from getting swallowed.
// https://stackoverflow.com/a/12102992/1263117
fileInput.value = null;
fileInput.addEventListener("change", e => {
resolve(e.target.files);
});
fileInput.click();
});
}
function urlIsBlobUrl(url) {
return /^blob:/.test(url);
}
// This is not perfect, but... meh: https://stackoverflow.com/a/36756650/1263117
export function filenameFromUrl(url) {
if (urlIsBlobUrl(url)) {
return null;
}
return url
.split("/")
.pop()
.split("#")[0]
.split("?")[0];
}