Browse Source

Update

mane
Raindrops 6 months ago
parent
commit
a6eabecc14
Signed by: Raindrops
GPG Key ID: EFBDC68435A574B7
  1. 15
      .idea/deployment.xml
  2. 6
      .idea/vcs.xml
  3. 7
      browser/build.js
  4. 6808
      browser/eqmc.js
  5. 79
      browser/src/eqmc.js
  6. 6727
      browser/src/pako.js
  7. 11
      browser/test.html
  8. 101
      elac-decode
  9. 46
      elac-encode
  10. 34
      elac-play
  11. 0
      package-lock.json
  12. 0
      package.json
  13. BIN
      test.elac

15
.idea/deployment.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" autoUpload="Always" serverName="Minteck" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="Minteck">
<serverdata>
<mappings>
<mapping deploy="/mnt/bucket/eqmc" local="$PROJECT_DIR$/browser" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
<option name="myAutoUpload" value="ALWAYS" />
</component>
</project>

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

7
browser/build.js

@ -0,0 +1,7 @@
const fs = require('fs');
let files = [];
files.push(fs.readFileSync("./src/pako.js").toString());
files.push(fs.readFileSync("./src/eqmc.js").toString());
fs.writeFileSync("./eqmc.js", files.join("\n\n\n"));

6808
browser/eqmc.js

File diff suppressed because it is too large Load Diff

79
browser/src/eqmc.js

@ -0,0 +1,79 @@
class EQMCData extends Object {
constructor(obj) {
super();
for (let key of Object.keys(obj)) {
this[key] = obj[key];
}
}
}
class EQMCAudioStream extends Object {
constructor(obj) {
super();
for (let key of Object.keys(obj)) {
this[key] = obj[key];
}
}
}
class EQMCError extends Error {
constructor(props) {
super(props);
this.name = "EQMCError";
}
}
window.EQMC = {
_base64ToArrayBuffer: (base64) => {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
},
isEQMCData: async (data) => {
return data instanceof EQMCData && data["_eqmc"];
},
isEQMCAudioStream: async (data) => {
return data instanceof EQMCAudioStream && data["data"];
},
create: async (file) => {
try {
return new EQMCData(JSON.parse(new TextDecoder("utf-8").decode(pako.inflate(new Uint8Array((await (await (await window.fetch(file)).blob()).arrayBuffer()))))));
} catch (e) {
console.error(e);
throw new EQMCError("Failed to construct EQMCData object");
}
},
decodeFile: async (data, file) => {
if (!await EQMC.isEQMCData(data)) throw new EQMCError("Invalid input, expected EQMCData");
if (data.files.length - 1 >= file) {
let s = data.files[file];
s["data"] = new Blob([pako.inflate(EQMC._base64ToArrayBuffer(s.data))]);
return new EQMCAudioStream(s);
} else {
throw new EQMCError("File index is out of range");
}
},
toAudio: async (data) => {
if (!await EQMC.isEQMCAudioStream(data)) throw new EQMCError("Invalid input, expected EQMCAudioStream");
return new Audio(window.URL.createObjectURL(data.data));
},
quickAudio: async (url, id) => {
let eqmc = await EQMC.create(url);
let file = await EQMC.decodeFile(eqmc, id);
return await EQMC.toAudio(file);
}
}

6727
browser/src/pako.js

File diff suppressed because it is too large Load Diff

11
browser/test.html

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>EQMC Browser Test</title>
<script src="./eqmc.js"></script>
</head>
<body>
https://bucket.minteck.org/demo.eqmc
</body>
</html>

101
elac-decode

@ -0,0 +1,101 @@
#!/usr/local/bin/node
global.fs = require('fs');
global.os = require('os');
global.path = require('path');
global.zlib = require('zlib');
global.child_process = require('child_process');
global.version = "1.1";
global.argv = process.argv;
argv.shift(); argv.shift();
console.log("Equestria Lossless Audio Codec");
console.log(" (c) Copyright, Equestria.dev");
console.log("ELAC Decoder");
console.log(" (c) Copyright, Equestria.dev");
console.log("version " + version);
console.log("");
try {
child_process.execSync("ffmpeg -version");
child_process.execSync("ffprobe -version");
child_process.execSync("ffplay -version");
} catch (e) {
console.error("Unable to start the ELAC Decoder:\n ffmpeg was not found or is incomplete");
process.exit(2);
}
if (argv.length < 1) {
console.error("Unable to start the ELAC Decoder:\n No input file has been specified");
process.exit(2);
}
global.inputFile = argv[0].trim();
global.file = path.basename(inputFile);
if (!fs.existsSync(inputFile)) {
console.error("Unable to decode \"" + file + "\":\n \"" + inputFile + "\": no such file or directory");
process.exit(2);
}
console.log("Reading Equestria Lossless Audio Codec data...");
try {
global.data = JSON.parse(zlib.inflateSync(fs.readFileSync(inputFile), {
level: -1,
strategy: 0,
memLevel: 9
}).toString());
} catch (e) {
console.error("Unable to decode \"" + file + "\":\n \"" + inputFile + "\": unable to decode file");
process.exit(2);
}
if (!data._eqmc) {
console.error("Unable to decode \"" + file + "\":\n \"" + inputFile + "\": not a valid ELAC file");
process.exit(2);
}
global.inputs = data.files;
for (let input of inputs) {
console.log("\n" + input._id + ":\n " + Object.keys(input.tags).map(i => { return i + ": " + input.tags[i]; }).join("\n ") + "\n");
try {
if (fs.existsSync(os.tmpdir() + "/elac-play-temp")) {
fs.rmSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
}
fs.mkdirSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
} catch (e) {
console.error("Unable to decode \"" + file + "\":\n Cannot create temporary working directory");
process.exit(2);
}
console.log("Decoding \"" + inputFile + ":/" + input._id + "\"...");
let outFile = os.tmpdir() + "/elac-play-temp/" + input._id + ".opus";
if (input.lossless) {
outFile = os.tmpdir() + "/elac-play-temp/" + input._id + ".flac";
}
fs.writeFileSync(outFile, zlib.inflateSync(Buffer.from(input.data, "base64"), {
level: -1,
strategy: 0,
memLevel: 9
}));
console.log("Moving to \"" + inputFile + "." + input._id + ".wav\"...");
child_process.execFileSync("ffmpeg", [ "-v", "quiet", "-i", outFile, "-map_metadata", "-1", "-fflags", "+bitexact", "-flags:v", "+bitexact", "-flags:a", "+bitexact", "-metadata", "id3v2_priv.XMP=", outFile + ".wav" ]);
fs.renameSync(outFile + ".wav", inputFile + "." + input._id + ".wav");
try {
fs.rmSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
} catch (e) {
console.error("Unable to encode \"" + file + "\":\n Cannot clear temporary working directory");
process.exit(2);
}
}
console.log("Done!");

46
eqmc-encode → elac-encode

@ -6,14 +6,14 @@ global.os = require('os');
global.child_process = require('child_process');
global.uuid = require('uuid')['v4'];
global.version = "1.0";
global.version = "1.1";
global.argv = process.argv;
argv.shift(); argv.shift();
console.log("Equestria Media Codec");
console.log("Equestria Lossless Audio Codec");
console.log(" (c) Copyright, Equestria.dev");
console.log("Eqmc Encoder");
console.log("ELAC Encoder");
console.log(" (c) Copyright, Equestria.dev");
console.log("version " + version);
console.log("");
@ -23,12 +23,12 @@ try {
child_process.execSync("ffprobe -version");
child_process.execSync("ffplay -version");
} catch (e) {
console.error("Unable to start the Eqmc Encoder:\n ffmpeg was not found or is incomplete");
console.error("Unable to start the ELAC Encoder:\n ffmpeg was not found or is incomplete");
process.exit(2);
}
if (argv.length < 1) {
console.error("Unable to start the Eqmc Encoder:\n No output file has been specified");
console.error("Unable to start the ELAC Encoder:\n No output file has been specified");
process.exit(2);
}
@ -36,10 +36,10 @@ global.output = argv[0].trim();
global.dir = path.dirname(output);
global.file = path.basename(output);
if (!output.endsWith(".eqmc")) {
console.warn("warning: specified output (\"" + output + "\") does not contain extension, using \"" + output + ".eqmc\" instead.");
file = file + ".eqmc";
output = output + ".eqmc";
if (!output.endsWith(".elac")) {
console.warn("warning: specified output (\"" + output + "\") does not contain extension, using \"" + output + ".elac\" instead.");
file = file + ".elac";
output = output + ".elac";
}
if (!fs.existsSync(dir)) {
@ -97,28 +97,35 @@ for (let input of valid_inputs) {
let streams = probe.streams.filter(i => i['codec_type'] === "audio");
let fileId = uuid();
let lossless = false;
let outFile = os.tmpdir() + "/elac-encode-temp/" + fileId + ".opus";
if (streams[0]['codec_name'].includes("pcm") || streams[0]['codec_name'].includes("flac") || streams[0]['codec_name'].includes("alac") || streams[0]['codec_name'].includes("dts")) {
lossless = true;
outFile = os.tmpdir() + "/elac-encode-temp/" + fileId + ".flac";
}
console.log("\n" + input + ":");
console.log(" Duration: " + new Date(probe.format['duration'] * 1000).toISOString().substring(11, 19));
console.log(" Container Type: " + probe.format['format_long_name']);
console.log(" Stream Type: " + streams[0]['codec_long_name']);
console.log(" Eqmc File ID: " + fileId);
console.log(" ELAC Stream ID: " + fileId);
console.log(" Lossless Mode: " + (lossless ? "yes" : "no") + " (" + (lossless ? "ELAC Physical Lossless" : "ELAC Emulated Lossless") + ")");
console.log("");
try {
if (fs.existsSync(os.tmpdir() + "/eqmc-encode-temp")) {
fs.rmSync(os.tmpdir() + "/eqmc-encode-temp", { recursive: true });
if (fs.existsSync(os.tmpdir() + "/elac-encode-temp")) {
fs.rmSync(os.tmpdir() + "/elac-encode-temp", { recursive: true });
}
fs.mkdirSync(os.tmpdir() + "/eqmc-encode-temp", { recursive: true });
fs.mkdirSync(os.tmpdir() + "/elac-encode-temp", { recursive: true });
} catch (e) {
console.error("Unable to encode \"" + file + "\":\n Cannot create temporary working directory");
process.exit(2);
}
let outFile = os.tmpdir() + "/eqmc-encode-temp/" + fileId + ".wav";
console.log("Encoding \"" + output + ":/" + fileId + "\"...");
try {
child_process.execFileSync("ffmpeg", [ "-v", "quiet", "-i", input, outFile ]);
child_process.execFileSync("ffmpeg", [ "-v", "quiet", "-i", input, "-map_metadata", "-1", outFile ]);
if (!fs.existsSync(outFile)) {
console.error("Unable to encode \"" + file + "\":\n Successfully encoded file " + fileId + ", but file does not exist");
process.exit(2);
@ -130,7 +137,8 @@ for (let input of valid_inputs) {
out.files.push({
_id: fileId,
data: zlib.deflateRawSync(fs.readFileSync(outFile), {
lossless,
data: zlib.deflateSync(fs.readFileSync(outFile), {
level: -1,
strategy: 0,
memLevel: 9
@ -139,7 +147,7 @@ for (let input of valid_inputs) {
})
try {
fs.rmSync(os.tmpdir() + "/eqmc-encode-temp", { recursive: true });
fs.rmSync(os.tmpdir() + "/elac-encode-temp", { recursive: true });
} catch (e) {
console.error("Unable to encode \"" + file + "\":\n Cannot clear temporary working directory");
process.exit(2);
@ -147,7 +155,7 @@ for (let input of valid_inputs) {
}
console.log("Writing to \"" + output + "\"...");
fs.writeFileSync(output, zlib.deflateRawSync(JSON.stringify(out), {
fs.writeFileSync(output, zlib.deflateSync(JSON.stringify(out), {
level: -1,
strategy: 0,
memLevel: 9

34
eqmc-play → elac-play

@ -5,14 +5,14 @@ global.path = require('path');
global.zlib = require('zlib');
global.child_process = require('child_process');
global.version = "1.0";
global.version = "1.1";
global.argv = process.argv;
argv.shift(); argv.shift();
console.log("Equestria Media Codec");
console.log("Equestria Lossless Audio Codec");
console.log(" (c) Copyright, Equestria.dev");
console.log("Eqmc Player");
console.log("ELAC Player");
console.log(" (c) Copyright, Equestria.dev");
console.log("version " + version);
console.log("");
@ -22,12 +22,12 @@ try {
child_process.execSync("ffprobe -version");
child_process.execSync("ffplay -version");
} catch (e) {
console.error("Unable to start the Eqmc Player:\n ffmpeg was not found or is incomplete");
console.error("Unable to start the ELAC Player:\n ffmpeg was not found or is incomplete");
process.exit(2);
}
if (argv.length < 1) {
console.error("Unable to start the Eqmc Player:\n No input file has been specified");
console.error("Unable to start the ELAC Player:\n No input file has been specified");
process.exit(2);
}
@ -39,9 +39,9 @@ if (!fs.existsSync(inputFile)) {
process.exit(2);
}
console.log("Reading Equestria Media Codec data...");
console.log("Reading Equestria Lossless Audio Codec data...");
try {
global.data = JSON.parse(zlib.inflateRawSync(fs.readFileSync(inputFile), {
global.data = JSON.parse(zlib.inflateSync(fs.readFileSync(inputFile), {
level: -1,
strategy: 0,
memLevel: 9
@ -52,7 +52,7 @@ try {
}
if (!data._eqmc) {
console.error("Unable to play \"" + file + "\":\n \"" + inputFile + "\": not a valid EQMC file");
console.error("Unable to play \"" + file + "\":\n \"" + inputFile + "\": not a valid ELAC file");
process.exit(2);
}
@ -62,18 +62,23 @@ for (let input of inputs) {
console.log("\n" + input._id + ":\n " + Object.keys(input.tags).map(i => { return i + ": " + input.tags[i]; }).join("\n ") + "\n");
try {
if (fs.existsSync(os.tmpdir() + "/eqmc-play-temp")) {
fs.rmSync(os.tmpdir() + "/eqmc-play-temp", { recursive: true });
if (fs.existsSync(os.tmpdir() + "/elac-play-temp")) {
fs.rmSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
}
fs.mkdirSync(os.tmpdir() + "/eqmc-play-temp", { recursive: true });
fs.mkdirSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
} catch (e) {
console.error("Unable to decode \"" + file + "\":\n Cannot create temporary working directory");
process.exit(2);
}
console.log("Decoding \"" + inputFile + ":/" + input._id + "\"...");
let outFile = os.tmpdir() + "/eqmc-play-temp/" + input._id + ".wav";
fs.writeFileSync(outFile, zlib.inflateRawSync(Buffer.from(input.data, "base64"), {
let outFile = os.tmpdir() + "/elac-play-temp/" + input._id + ".opus";
if (input.lossless) {
outFile = os.tmpdir() + "/elac-play-temp/" + input._id + ".flac";
}
fs.writeFileSync(outFile, zlib.inflateSync(Buffer.from(input.data, "base64"), {
level: -1,
strategy: 0,
memLevel: 9
@ -82,9 +87,8 @@ for (let input of inputs) {
console.log("Playing \"" + inputFile + ":/" + input._id + "\"...");
child_process.spawnSync("ffplay", [ "-hide_banner", "-autoexit", "-nodisp", "--", outFile ], { stdio: "inherit" });
console.log(outFile);
try {
fs.rmSync(os.tmpdir() + "/eqmc-play-temp", { recursive: true });
fs.rmSync(os.tmpdir() + "/elac-play-temp", { recursive: true });
} catch (e) {
console.error("Unable to encode \"" + file + "\":\n Cannot clear temporary working directory");
process.exit(2);

0
package-lock.json generated

0
package.json

BIN
test.elac

Binary file not shown.