This commit is contained in:
2022-09-30 05:39:11 +00:00
parent 41ee9463ae
commit 4687fa49bc
11418 changed files with 1312504 additions and 0 deletions

11
buildfiles/app/node_modules/metaflac-js2/.prettierrc generated vendored Normal file
View File

@ -0,0 +1,11 @@
{
"printWidth": 120,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"endOfLine": "lf",
"arrowParens": "always"
}

39
buildfiles/app/node_modules/metaflac-js2/README.md generated vendored Normal file
View File

@ -0,0 +1,39 @@
# metaflac-js2
A pure JavaScript implementation of the metaflac (the official FLAC tool written in C++)
> This is a tool that has just been completed, I hope to help you, and I hope we can optimize it together.
Use as module:
```
npm i metaflac-js2 --save
```
```
const Metaflac = require('metaflac-js2');
const flac = new Metaflac('/path/to/flac.flac or buffer');
flac.setTag('TITLE=My Music');
flac.save();
```
Use as cli:
Usage is basically consistent with official tools.
```
npm i metaflac-js2 -g
metaflac-js -h
```
Note: here is the official FLAC tools [doc](https://xiph.org/flac/documentation_tools_metaflac.html)
- This is a fork of [metaflac-js](https://github.com/ishowshao/metaflac-js) with minor improvements for detecting image dimensions and mime type.
#### Changelog:
- Removed `importPictureFrom`and `importPictureFromBuffer`
- Added `importPicture`
importPicture takes either path or buffer

151
buildfiles/app/node_modules/metaflac-js2/cli.js generated vendored Executable file
View File

@ -0,0 +1,151 @@
#!/usr/bin/env node
const path = require('path');
const program = require('commander');
const info = require('./package.json');
const Metaflac = require('./index');
let file;
program.version(info.version, '-v, --version');
program.arguments('<FLACfile>').action((FLACfile) => {
file = FLACfile;
});
program.option('--show-md5sum', 'Show the MD5 signature from the STREAMINFO block.');
program.option('--show-min-blocksize', 'Show the minimum block size from the STREAMINFO block.');
program.option('--show-max-blocksize', 'Show the maximum block size from the STREAMINFO block.');
program.option('--show-min-framesize', 'Show the minimum frame size from the STREAMINFO block.');
program.option('--show-max-framesize', 'Show the maximum frame size from the STREAMINFO block.');
program.option('--show-sample-rate', 'Show the sample rate from the STREAMINFO block.');
program.option('--show-channels', 'Show the number of channels from the STREAMINFO block.');
program.option('--show-bps', 'Show the # of bits per sample from the STREAMINFO block.');
program.option('--show-total-samples', 'Show the total # of samples from the STREAMINFO block.');
program.option('--show-vendor-tag', 'Show the vendor string from the VORBIS_COMMENT block.');
program.option('--show-tag <NAME>', 'Show all tags where the the field name matches NAME.');
program.option('--remove-tag <NAME>', 'Remove all tags whose field name is NAME.');
program.option('--remove-first-tag <NAME>', 'Remove first tag whose field name is NAME.');
program.option('--remove-all-tags', 'Remove all tags, leaving only the vendor string.');
program.option(
'--set-tag <FIELD>',
'Add a tag. The FIELD must comply with the Vorbis comment spec, of the form NAME=VALUE. If there is currently no tag block, one will be created.'
);
program.option(
'--set-tag-from-file <FIELD>',
'Like --set-tag, except the VALUE is a filename whose contents will be read verbatim to set the tag value.'
);
program.option('--import-tags-from <FILE>', 'Import tags from a file.');
program.option(
'--export-tags-to <FILE>',
'Export tags to a file. Use - for stdout. Each line will be of the form NAME=VALUE.'
);
program.option('--import-picture-from <FILENAME>', 'Import a picture and store it in a PICTURE metadata block.');
program.option('--export-picture-to <FILE>', 'Export PICTURE block to a file.');
program.option('--list-picture', 'List all picture block info.');
program.parse(process.argv);
if (typeof file === 'undefined') {
console.error('ERROR: you must specify one FLAC file;');
process.exit(1);
}
try {
const flac = new Metaflac(file);
if (program.showMd5sum) {
console.log(flac.getMd5sum());
}
if (program.showMinBlocksize) {
console.log(flac.getMinBlocksize());
}
if (program.showMaxBlocksize) {
console.log(flac.getMaxBlocksize());
}
if (program.showMinFramesize) {
console.log(flac.getMinFramesize());
}
if (program.showMaxFramesize) {
console.log(flac.getMaxFramesize());
}
if (program.showSampleRate) {
console.log(flac.getSampleRate());
}
if (program.showChannels) {
console.log(flac.getChannels());
}
if (program.showBps) {
console.log(flac.getBps());
}
if (program.showTotalSamples) {
console.log(flac.getTotalSamples());
}
if (program.showVendorTag) {
console.log(flac.getVendorTag());
}
if (program.showTag) {
console.log(flac.getTag(program.showTag));
}
if (program.removeTag) {
flac.removeTag(program.removeTag);
console.log(flac.getAllTags().join('\n'));
}
if (program.removeFirstTag) {
flac.removeFirstTag(program.removeFirstTag);
console.log(flac.getAllTags().join('\n'));
}
if (program.removeAllTags) {
flac.removeAllTags();
console.log(flac.getAllTags().join('\n'));
}
if (program.setTag) {
flac.setTag(program.setTag);
console.log(flac.getAllTags().join('\n'));
flac.save();
}
if (program.setTagFromFile) {
flac.setTagFromFile(program.setTagFromFile);
console.log(flac.getAllTags().join('\n'));
}
if (program.importTagsFrom) {
flac.importTagsFrom(program.importTagsFrom);
console.log(flac.getAllTags().join('\n'));
}
if (program.exportTagsTo) {
if (program.exportTagsTo === '-') {
console.log(flac.getAllTags().join('\n'));
} else {
let filepath;
if (!path.isAbsolute(program.exportTagsTo)) {
filepath = path.resolve(process.cwd(), program.exportTagsTo);
} else {
filepath = program.exportTagsTo;
}
flac.exportTagsTo(filepath);
}
}
if (program.importPictureFrom) {
let filepath;
if (!path.isAbsolute(program.importPictureFrom)) {
filepath = path.resolve(process.cwd(), program.importPictureFrom);
} else {
filepath = program.importPictureFrom;
}
flac.importPictureFrom(filepath);
flac.save();
}
if (program.exportPictureTo) {
let filepath;
if (!path.isAbsolute(program.exportPictureTo)) {
filepath = path.resolve(process.cwd(), program.exportPictureTo);
} else {
filepath = program.exportPictureTo;
}
flac.exportPictureTo(filepath);
}
if (program.listPicture) {
flac.getPicturesSpecs().forEach((spec) => console.log(spec));
}
} catch (e) {
console.log(`Error: ${e.message}`);
process.exit(1);
}

480
buildfiles/app/node_modules/metaflac-js2/index.js generated vendored Normal file
View File

@ -0,0 +1,480 @@
const fs = require('fs');
const imageSize = require('probe-image-size');
const formatVorbisComment = require('./lib/formatVorbisComment');
const BLOCK_TYPE = {
0: 'STREAMINFO',
1: 'PADDING',
2: 'APPLICATION',
3: 'SEEKTABLE',
4: 'VORBIS_COMMENT', // There may be only one VORBIS_COMMENT block in a stream.
5: 'CUESHEET',
6: 'PICTURE',
};
const STREAMINFO = 0;
const PADDING = 1;
const APPLICATION = 2;
const SEEKTABLE = 3;
const VORBIS_COMMENT = 4;
const CUESHEET = 5;
const PICTURE = 6;
class Metaflac {
constructor(flac) {
if (typeof flac !== 'string' && !Buffer.isBuffer(flac)) {
throw new Error('Metaflac(flac) flac must be string or buffer.');
}
this.flac = flac;
this.buffer = null;
this.marker = '';
this.streamInfo = null;
this.blocks = [];
this.padding = null;
this.vorbisComment = null;
this.vendorString = '';
this.tags = [];
this.pictures = [];
this.picturesSpecs = [];
this.picturesDatas = [];
this.framesOffset = 0;
this.init();
}
init() {
typeof this.flac === 'string' ? (this.buffer = fs.readFileSync(this.flac)) : (this.buffer = this.flac);
let offset = 0;
const marker = this.buffer.slice(0, (offset += 4)).toString('ascii');
if (marker !== 'fLaC') {
throw new Error('The file does not appear to be a FLAC file.');
}
let blockType = 0;
let isLastBlock = false;
while (!isLastBlock) {
blockType = this.buffer.readUInt8(offset++);
isLastBlock = blockType > 128;
blockType = blockType % 128;
// console.log('Block Type: %d %s', blockType, BLOCK_TYPE[blockType]);
const blockLength = this.buffer.readUIntBE(offset, 3);
offset += 3;
// console.log('Offset: %d', offset);
if (blockType === STREAMINFO) {
this.streamInfo = this.buffer.slice(offset, offset + blockLength);
}
/*
if (blockType === PADDING) {
this.padding = this.buffer.slice(offset, offset + blockLength);
}
*/
if (blockType === VORBIS_COMMENT) {
this.vorbisComment = this.buffer.slice(offset, offset + blockLength);
this.parseVorbisComment();
}
/*
if (blockType === PICTURE) {
this.pictures.push(this.buffer.slice(offset, offset + blockLength));
this.parsePictureBlock();
}
*/
if ([APPLICATION, SEEKTABLE, CUESHEET].includes(blockType)) {
this.blocks.push([blockType, this.buffer.slice(offset, offset + blockLength)]);
}
// console.log('Block Length: %d', blockLength);
offset += blockLength;
}
this.framesOffset = offset;
// console.log('Total Length: %d', offset);
}
parseVorbisComment() {
const vendorLength = this.vorbisComment.readUInt32LE(0);
// console.log('Vendor length: %d', vendorLength);
this.vendorString = this.vorbisComment.slice(4, vendorLength + 4).toString('utf8');
// console.log('Vendor string: %s', this.vendorString);
/*
const userCommentListLength = this.vorbisComment.readUInt32LE(4 + vendorLength);
// console.log('user_comment_list_length: %d', userCommentListLength);
const userCommentListBuffer = this.vorbisComment.slice(4 + vendorLength + 4);
for (let offset = 0; offset < userCommentListBuffer.length; ) {
const length = userCommentListBuffer.readUInt32LE(offset);
offset += 4;
const comment = userCommentListBuffer.slice(offset, offset += length).toString('utf8');
// console.log('Comment length: %d, this.buffer: %s', length, comment);
this.tags.push(comment);
}
*/
}
parsePictureBlock() {
this.pictures.forEach((picture) => {
let offset = 0;
const type = picture.readUInt32BE(offset);
offset += 4;
const mimeTypeLength = picture.readUInt32BE(offset);
offset += 4;
const mime = picture.slice(offset, offset + mimeTypeLength).toString('ascii');
offset += mimeTypeLength;
const descriptionLength = picture.readUInt32BE(offset);
offset += 4;
const description = picture.slice(offset, (offset += descriptionLength)).toString('utf8');
const width = picture.readUInt32BE(offset);
offset += 4;
const height = picture.readUInt32BE(offset);
offset += 4;
const depth = picture.readUInt32BE(offset);
offset += 4;
const colors = picture.readUInt32BE(offset);
offset += 4;
const pictureDataLength = picture.readUInt32BE(offset);
offset += 4;
this.picturesDatas.push(picture.slice(offset, offset + pictureDataLength));
this.picturesSpecs.push(
this.buildSpecification({
type,
mime,
description,
width,
height,
depth,
colors,
})
);
});
}
getPicturesSpecs() {
return this.picturesSpecs;
}
/**
* Get the MD5 signature from the STREAMINFO block.
*/
getMd5sum() {
return this.streamInfo.slice(18, 34).toString('hex');
}
/**
* Get the minimum block size from the STREAMINFO block.
*/
getMinBlocksize() {
return this.streamInfo.readUInt16BE(0);
}
/**
* Get the maximum block size from the STREAMINFO block.
*/
getMaxBlocksize() {
return this.streamInfo.readUInt16BE(2);
}
/**
* Get the minimum frame size from the STREAMINFO block.
*/
getMinFramesize() {
return this.streamInfo.readUIntBE(4, 3);
}
/**
* Get the maximum frame size from the STREAMINFO block.
*/
getMaxFramesize() {
return this.streamInfo.readUIntBE(7, 3);
}
/**
* Get the sample rate from the STREAMINFO block.
*/
getSampleRate() {
// 20 bits number
return this.streamInfo.readUIntBE(10, 3) >> 4;
}
/**
* Get the number of channels from the STREAMINFO block.
*/
getChannels() {
// 3 bits
return this.streamInfo.readUIntBE(10, 3) & (0x00000f >> 1);
}
/**
* Get the # of bits per sample from the STREAMINFO block.
*/
getBps() {
return this.streamInfo.readUIntBE(12, 2) & (0x01f0 >> 4);
}
/**
* Get the total # of samples from the STREAMINFO block.
*/
getTotalSamples() {
return this.streamInfo.readUIntBE(13, 5) & 0x0fffffffff;
}
/**
* Show the vendor string from the VORBIS_COMMENT block.
*/
getVendorTag() {
return this.vendorString;
}
/**
* Get all tags where the the field name matches NAME.
*
* @param {string} name
*/
getTag(name) {
return this.tags
.filter((item) => {
const itemName = item.split('=')[0];
return itemName === name;
})
.join('\n');
}
/**
* Remove all tags whose field name is NAME.
*
* @param {string} name
*/
removeTag(name) {
this.tags = this.tags.filter((item) => {
const itemName = item.split('=')[0];
return itemName !== name;
});
}
/**
* Remove first tag whose field name is NAME.
*
* @param {string} name
*/
removeFirstTag(name) {
const found = this.tags.findIndex((item) => {
return item.split('=')[0] === name;
});
if (found !== -1) {
this.tags.splice(found, 1);
}
}
/**
* Remove all tags, leaving only the vendor string.
*/
removeAllTags() {
this.tags = [];
}
/**
* Add a tag.
* The FIELD must comply with the Vorbis comment spec, of the form NAME=VALUE. If there is currently no tag block, one will be created.
*
* @param {string} field
*/
setTag(field) {
if (field.indexOf('=') === -1) {
throw new Error(`malformed vorbis comment field "${field}", field contains no '=' character`);
}
this.tags.push(field);
}
/**
* Like setTag, except the VALUE is a filename whose contents will be read verbatim to set the tag value.
*
* @param {string} field
*/
setTagFromFile(field) {
const position = field.indexOf('=');
if (position === -1) {
throw new Error(`malformed vorbis comment field "${field}", field contains no '=' character`);
}
const name = field.substring(0, position);
const filename = field.substr(position + 1);
let value;
try {
value = fs.readFileSync(filename, 'utf8');
} catch (e) {
throw new Error(`can't open file '${filename}' for '${name}' tag value`);
}
this.tags.push(`${name}=${value}`);
}
/**
* Import tags from a file.
* Each line should be of the form NAME=VALUE.
*
* @param {string} filename
*/
importTagsFrom(filename) {
const tags = fs.readFileSync(filename, 'utf8').split('\n');
tags.forEach((line) => {
if (line.indexOf('=') === -1) {
throw new Error(`malformed vorbis comment "${line}", contains no '=' character`);
}
});
this.tags = this.tags.concat(tags);
}
/**
* Export tags to a file.
* Each line will be of the form NAME=VALUE.
*
* @param {string} filename
*/
exportTagsTo(filename) {
fs.writeFileSync(filename, this.tags.join('\n'), 'utf8');
}
/**
* Import a picture and store it in a PICTURE metadata block.
*
* @param {string} filename
*/
importPicture(picture) {
if (!Buffer.isBuffer(picture)) {
picture = fs.readFileSync(picture);
}
const dimensions = imageSize.sync(picture);
if (!dimensions) {
throw new Error('Unable to determine image dimensions');
}
if (dimensions.mime !== 'image/jpeg' && dimensions.mime !== 'image/png') {
throw new Error(`only support image/jpeg and image/png picture temporarily, current import ${mime}`);
}
const spec = this.buildSpecification({
mime: dimensions.mime,
width: dimensions.width,
height: dimensions.height,
});
this.pictures.push(this.buildPictureBlock(picture, spec));
this.picturesSpecs.push(spec);
}
/**
* Export PICTURE block to a file.
*
* @param {string} filename
*/
exportPictureTo(filename) {
if (this.picturesDatas.length > 0) {
fs.writeFileSync(filename, this.picturesDatas[0]);
}
}
/**
* Return all tags.
*/
getAllTags() {
return this.tags;
}
buildSpecification(spec = {}) {
const defaults = {
type: 3,
mime: 'image/jpeg',
description: '',
width: 0,
height: 0,
depth: 24,
colors: 0,
};
return Object.assign(defaults, spec);
}
/**
* Build a picture block.
*
* @param {Buffer} picture
* @param {Object} specification
* @returns {Buffer}
*/
buildPictureBlock(picture, specification = {}) {
const pictureType = Buffer.alloc(4);
const mimeLength = Buffer.alloc(4);
const mime = Buffer.from(specification.mime, 'ascii');
const descriptionLength = Buffer.alloc(4);
const description = Buffer.from(specification.description, 'utf8');
const width = Buffer.alloc(4);
const height = Buffer.alloc(4);
const depth = Buffer.alloc(4);
const colors = Buffer.alloc(4);
const pictureLength = Buffer.alloc(4);
pictureType.writeUInt32BE(specification.type);
mimeLength.writeUInt32BE(specification.mime.length);
descriptionLength.writeUInt32BE(specification.description.length);
width.writeUInt32BE(specification.width);
height.writeUInt32BE(specification.height);
depth.writeUInt32BE(specification.depth);
colors.writeUInt32BE(specification.colors);
pictureLength.writeUInt32BE(picture.length);
return Buffer.concat([
pictureType,
mimeLength,
mime,
descriptionLength,
description,
width,
height,
depth,
colors,
pictureLength,
picture,
]);
}
buildMetadataBlock(type, block, isLast = false) {
const header = Buffer.alloc(4);
if (isLast) {
type += 128;
}
header.writeUIntBE(type, 0, 1);
header.writeUIntBE(block.length, 1, 3);
return Buffer.concat([header, block]);
}
buildMetadata() {
const bufferArray = [];
bufferArray.push(this.buildMetadataBlock(STREAMINFO, this.streamInfo));
this.blocks.forEach((block) => {
bufferArray.push(this.buildMetadataBlock(...block));
});
bufferArray.push(this.buildMetadataBlock(VORBIS_COMMENT, formatVorbisComment(this.vendorString, this.tags)));
this.pictures.forEach((block) => {
bufferArray.push(this.buildMetadataBlock(PICTURE, block));
});
if (this.padding == null) this.padding = Buffer.alloc(16384);
bufferArray.push(this.buildMetadataBlock(PADDING, this.padding, true));
return bufferArray;
}
buildStream() {
const metadata = this.buildMetadata();
return [this.buffer.slice(0, 4), ...metadata, this.buffer.slice(this.framesOffset)];
}
/**
* Save change to file or return changed buffer.
*/
save() {
if (typeof this.flac === 'string') {
fs.writeFileSync(this.flac, Buffer.concat(this.buildStream()));
} else {
return Buffer.concat(this.buildStream());
}
}
}
module.exports = Metaflac;

View File

@ -0,0 +1,21 @@
module.exports = (vendorString, commentList) => {
const bufferArray = [];
const vendorStringBuffer = Buffer.from(vendorString, 'utf8');
const vendorLengthBuffer = Buffer.alloc(4);
vendorLengthBuffer.writeUInt32LE(vendorStringBuffer.length);
const userCommentListLengthBuffer = Buffer.alloc(4);
userCommentListLengthBuffer.writeUInt32LE(commentList.length);
bufferArray.push(vendorLengthBuffer, vendorStringBuffer, userCommentListLengthBuffer);
for (let i = 0; i < commentList.length; i++) {
const comment = commentList[i];
const commentBuffer = Buffer.from(comment, 'utf8');
const lengthBuffer = Buffer.alloc(4);
lengthBuffer.writeUInt32LE(commentBuffer.length);
bufferArray.push(lengthBuffer, commentBuffer);
}
return Buffer.concat(bufferArray);
};

62
buildfiles/app/node_modules/metaflac-js2/package.json generated vendored Normal file
View File

@ -0,0 +1,62 @@
{
"_args": [
[
"metaflac-js2@1.0.7",
"/home/shihaam/www/freezer.shihaam.me/app"
]
],
"_from": "metaflac-js2@1.0.7",
"_id": "metaflac-js2@1.0.7",
"_inBundle": false,
"_integrity": "sha512-iHLEepKmMp7BuxsGwaUnaef3b+OPouDtEkDLsgzspkbAsjTLXA/Yawn1e1wsYqAF4EtmERdpww/bYFCnDWfG8w==",
"_location": "/metaflac-js2",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "metaflac-js2@1.0.7",
"name": "metaflac-js2",
"escapedName": "metaflac-js2",
"rawSpec": "1.0.7",
"saveSpec": null,
"fetchSpec": "1.0.7"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/metaflac-js2/-/metaflac-js2-1.0.7.tgz",
"_spec": "1.0.7",
"_where": "/home/shihaam/www/freezer.shihaam.me/app",
"author": {
"name": "Sayem Chowdhury"
},
"bin": {
"metaflac-js": "cli.js"
},
"bugs": {
"url": "https://github.com/d-fi/metaflac-js2/issues"
},
"dependencies": {
"commander": "^3.0.1",
"probe-image-size": "^5.0.0"
},
"description": "A pure JavaScript implementation of the metaflac (official FLAC tool)",
"homepage": "https://github.com/d-fi/metaflac-js2#readme",
"keywords": [
"metaflac",
"flac",
"metadata",
"writer"
],
"license": "ISC",
"main": "index.js",
"name": "metaflac-js2",
"repository": {
"type": "git",
"url": "git+https://github.com/d-fi/metaflac-js2.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "1.0.7"
}