publikator/src/organise.js

115 lines
3.1 KiB
JavaScript
Raw Normal View History

2018-08-14 18:26:02 +02:00
const path = require('path');
2018-11-11 10:28:14 +01:00
const fs = require('fs-extra');
2018-08-14 18:26:02 +02:00
const _ = require('lodash');
const sanitize = require('sanitize-filename');
const debug = require('debug')('publikator:organise');
2018-08-20 15:18:47 +02:00
const mime = require('mime-types');
2018-08-17 15:48:56 +02:00
const tags = require('./tags');
2018-08-14 18:26:02 +02:00
2018-08-24 11:43:27 +02:00
/**
* Given a track file, return the album name.
*/
const getAlbumName = file =>
file.common.album.replace(/[\W_]+/g, '-').toLowerCase();
2018-08-20 15:18:47 +02:00
2018-08-24 11:43:27 +02:00
/**
* Given a track file, return the new file name.
*/
2018-08-14 18:26:02 +02:00
const getFileName = file =>
`${file.common.track.no}-${file.common.title
.replace(/[\W_]+/g, '-')
.toLowerCase()}${path.extname(file.path)}`;
2018-08-14 18:26:02 +02:00
2018-08-24 11:43:27 +02:00
/**
* Strips the extension from a file name;
*/
const stripExtension = fileName => {
const i = fileName.lastIndexOf('.');
return fileName.substr(0, i);
};
2018-08-20 15:18:47 +02:00
/**
* Extracts the cover art and saves it to a file with the same name.
*/
const extractCoverArt = async filePath => {
const pictures = await tags.extractCoverArt(filePath);
if (pictures) {
2018-08-20 18:42:59 +02:00
const picture = pictures[0];
const pictureExt = mime.extension(picture.format);
const picturePath = `${filePath.replace(
path.extname(filePath),
''
)}.${pictureExt}`;
await fs.writeFile(picturePath, picture.data);
return picturePath;
2018-08-20 15:18:47 +02:00
}
2018-08-20 18:42:59 +02:00
return null;
2018-08-20 15:18:47 +02:00
};
2018-08-14 18:26:02 +02:00
module.exports = {
2018-08-17 15:48:56 +02:00
/**
* Organises tracks into a new folder structure in `root`, as follows:
*
* {artist} - {album}/
* {track} - {title}.{ext}
* {track} - {title}.{ext}
* ...
*
* Returns `taggedFiles` with the paths changed to the new paths.
*/
byAlbum: async (root, taggedFiles) => {
2018-08-24 11:43:27 +02:00
const assetRoot = path.resolve(root, 'assets', 'albums');
2018-08-17 15:48:56 +02:00
const files = taggedFiles.filter(file =>
tags.hasTags(file, [
'common.artists',
'common.album',
'common.track',
'common.title',
])
2018-08-17 15:48:56 +02:00
);
2018-08-14 18:26:02 +02:00
debug(`grouping tracks by album`);
2018-08-24 11:43:27 +02:00
const folders = _.uniq(files.map(file => getAlbumName(file)));
2018-08-14 18:26:02 +02:00
debug(`found ${folders.length} album(s)`);
debug(folders);
debug(`creating album directories`);
await Promise.all(
2018-08-24 11:43:27 +02:00
folders.map(album =>
fs.ensureDir(path.resolve(assetRoot, sanitize(album)))
)
2018-08-14 18:26:02 +02:00
);
2018-08-20 15:18:47 +02:00
debug(`copying tracks & extracting covers`);
2018-08-14 18:26:02 +02:00
return Promise.all(
2018-08-17 15:48:56 +02:00
files.map(async file => {
2018-08-24 11:43:27 +02:00
const folderName = getAlbumName(file);
2018-08-20 14:35:21 +02:00
const fileName = getFileName(file);
2018-08-24 11:43:27 +02:00
const newPath = path.resolve(assetRoot, folderName, fileName);
2018-08-17 15:48:56 +02:00
await fs.copyFile(file.path, newPath);
2018-08-20 18:42:59 +02:00
const coverPath = await extractCoverArt(newPath);
const trackSlug = stripExtension(fileName);
2018-08-20 14:35:21 +02:00
return _.assign(
{},
{
path: newPath,
2018-08-29 15:48:15 +02:00
audio: `/assets/albums/${folderName}/${fileName}`,
slug: `${folderName}/${trackSlug}`,
2018-08-29 15:48:15 +02:00
albumSlug: folderName,
trackSlug,
2018-08-20 14:35:21 +02:00
},
2018-08-20 18:42:59 +02:00
coverPath
? {
coverPath,
2018-08-24 11:43:27 +02:00
cover: `/assets/albums/${folderName}/${path.basename(
coverPath
)}`,
2018-08-20 18:42:59 +02:00
}
: {},
2018-08-20 14:35:21 +02:00
_.omit(file, 'path')
);
2018-08-14 18:26:02 +02:00
})
);
},
};