Skip to content

Commit

Permalink
touch lookup logic, extract extra metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
miraclx committed Oct 2, 2021
1 parent a377213 commit 1506d8e
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 73 deletions.
53 changes: 34 additions & 19 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ const symbols = require('./src/symbols');
const fileMgr = require('./src/file_mgr');
const pFlatten = require('./src/p_flatten');
const FreyrCore = require('./src/freyr');
const MusicBrainz = require('./src/musicbrainz.js');
const AuthServer = require('./src/cli_server');
const AsyncQueue = require('./src/async_queue');
const parseRange = require('./src/parse_range');
const musicBrainz = require('./src/musicbrainz.js');
const StackLogger = require('./src/stack_logger');
const packageJson = require('./package.json');
const streamUtils = require('./src/stream_utils');
Expand All @@ -44,7 +44,13 @@ function parseMeta(params) {
return Object.entries(params || {})
.filter(([, value]) => ![undefined, null].includes(value))
.map(([key, value]) =>
Array.isArray(value) ? value.map(tx => (tx ? [`--${key}`, ...(Array.isArray(tx) ? tx : [tx])] : '')) : [`--${key}`, value],
Array.isArray(value)
? value
.filter(val => val !== undefined)
.map((tx, args) =>
(args = Array.isArray(tx) ? tx : [tx]).every(val => val !== undefined) ? [`--${key}`, ...args] : [],
)
: [`--${key}`, value],
)
.flat(Infinity);
}
Expand Down Expand Up @@ -78,7 +84,7 @@ function wrapCliInterface(binaryName, binaryPath) {
}

if (typeof file === 'string') {
spawn(binaryPath, [file, ...parseMeta(args)], { env: extendPathOnEnv(path) }).on('close', cb);
spawn(binaryPath, [file, ...parseMeta(args)], {env: extendPathOnEnv(path)}).on('close', cb);
}
};
}
Expand Down Expand Up @@ -850,14 +856,18 @@ async function init(queries, options) {
gapless: options.gapless, // pgap
rDNSatom: [
// ----
['Digital Media', 'name=MEDIA', 'domain=com.apple.iTunes'],
[track.isrc, 'name=ISRC', 'domain=com.apple.iTunes'],
[track.musicBrainz.trackId, 'name=MusicBrainzTrackId', 'domain=com.apple.iTunes'],
[track.musicBrainz.artistId, 'name=MusicBrainzArtistId', 'domain=com.apple.iTunes'],
[track.musicBrainz.albumId, 'name=MusicBrainzAlbumId', 'domain=com.apple.iTunes'],
[track.musicBrainz.albumArtistId, 'name=MusicBrainzAlbumArtistId', 'domain=com.apple.iTunes'],
[track.artists[0], 'name=ARTISTS', 'domain=com.apple.iTunes'],
[track.label, 'name=LABEL', 'domain=com.apple.iTunes'],
[track.musicBrainz.trackId, 'name="MusicBrainz Track Id"', 'domain=com.apple.iTunes'],
[track.musicBrainz.artistId, 'name="MusicBrainz Artist Id"', 'domain=com.apple.iTunes'],
[track.musicBrainz.artistId, 'name="MusicBrainz Album Artist Id"', 'domain=com.apple.iTunes'],
[track.musicBrainz.releaseId, 'name="MusicBrainz Album Id"', 'domain=com.apple.iTunes'],
[track.musicBrainz.releaseGroupId, 'name="MusicBrainz Release Group Id"', 'domain=com.apple.iTunes'],
[track.musicBrainz.barcode, 'name=BARCODE', 'domain=com.apple.iTunes'],
[track.musicBrainz.releaseStatus, 'name="MusicBrainz Album Status"', 'domain=com.apple.iTunes'],
[track.musicBrainz.script, 'name=SCRIPT', 'domain=com.apple.iTunes'],
[track.musicBrainz.media, 'name=MEDIA', 'domain=com.apple.iTunes'],
[`${meta.service[symbols.meta].DESC}: ${track.uri}`, 'name=SOURCE', 'domain=com.apple.iTunes'],
[
`${audioSource.service[symbols.meta].DESC}: ${audioSource.source.videoId}`,
Expand All @@ -882,12 +892,12 @@ async function init(queries, options) {
encodingTool: `freyr-js cli v${packageJson.version}`, // ©too
encodedBy: 'd3vc0dr', // ©enc
artwork: files.image.file.name, // covr
// sortOrder: [
// ['name', 'NAME'], // sonm
// ['album', 'NAME'], // soal
// ['artist', 'NAME'], // soar
// ['albumartist', 'NAME'], // soaa
// ],
sortOrder: [
// ['name', 'NAME'], // sonm
// ['album', 'NAME'], // soal
['artist', track.musicBrainz.artistSortOrder], // soar
['albumartist', track.musicBrainz.artistSortOrder], // soaa
],
})
.finally(() => files.image.file.removeCallback())
.catch(err => Promise.reject({err, code: 8}));
Expand Down Expand Up @@ -989,6 +999,10 @@ async function init(queries, options) {
}
trackLogger.log('| [\u2022] Track exists. Overwriting...');
}
track.musicBrainz = await processPromise(props.extraTrackMeta, trackLogger, {
onInit: '| \u27a4 Pulling extra metadata...',
onErr: '[skipped]',
});
trackLogger.log('| \u27a4 Collating sources...');
const audioSource = await props.collectSources((service, sourcesPromise) =>
processPromise(sourcesPromise, trackLogger, {
Expand All @@ -1004,8 +1018,6 @@ async function init(queries, options) {
});
if (!audioFeeds || audioFeeds.err) return {meta, err: (audioFeeds || {}).err, code: 2};

track.musicBrainz = await MusicBrainz.gatherMusicBrainzMetadata(track, trackLogger);

const feedMeta = audioFeeds.formats.sort((meta1, meta2) => (meta1.abr > meta2.abr ? -1 : meta1.abr < meta2.abr ? 1 : 0))[0];
meta.fingerprint = crypto.createHash('md5').update(`${audioSource.source.videoId} ${feedMeta.format_id}`).digest('hex');
const files = await downloadQueue
Expand Down Expand Up @@ -1047,11 +1059,14 @@ async function init(queries, options) {
const outFilePath = xpath.join(outFileDir, outFileName);
const fileExists = fs.existsSync(outFilePath);
const processTrack = !fileExists || options.force;
let collectSources;
if (processTrack) collectSources = buildSourceCollectorFor(track, results => results[0]);
let collectSources, extraTrackMeta;
if (processTrack) {
collectSources = buildSourceCollectorFor(track, results => results[0]);
if (track.isrc) extraTrackMeta = musicBrainz.lookupISRC(track.isrc, options.storefront);
}
const meta = {trackName, outFileDir, outFilePath, track, service};
return trackQueue
.push({track, meta, props: {collectSources, fileExists, processTrack, logger}})
.push({track, meta, props: {collectSources, extraTrackMeta, fileExists, processTrack, logger}})
.then(trackObject => ({...trackObject, meta}))
.catch(errObject => ({meta, code: 10, ...errObject}));
},
Expand Down
108 changes: 54 additions & 54 deletions src/musicbrainz.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
async function gatherMusicBrainzMetadata(track, trackLogger)
{
var musicBrainz = [];
if (track.isrc !== "") {
trackLogger.print('| [\u2022] Obtaining MusicBrainz metadata...');

const got = require('got');
var parser = require('xml2js');

await got(`https://musicbrainz.org/ws/2/isrc/${track.isrc}?inc=artist-credits+releases`).then(response => {
trackLogger.write('[done]\n');
try {
// Should 'explicitArray: false' be used ?
parser.parseString(response.body, { trim: true, mergeAttrs: true }, function (err, result) {
const recording = result.metadata.isrc[0]['recording-list'][0]['recording'][0];

try {
musicBrainz.trackId = recording['id'][0];
} catch { };
trackLogger.log(`| \u27a4 TrackId: ${musicBrainz.trackId}`);
try {
musicBrainz.artistId = recording['artist-credit'][0]['name-credit'][0]['artist'][0]['id'][0];
} catch { };
trackLogger.log(`| \u27a4 ArtistId: ${musicBrainz.artistId}`);

// Searching for a matching album
const releases = recording['release-list'][0]['release'].filter(obj => {
const title = obj.title[0].replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); // Removing weird characters that can cause fails
return track.album.localeCompare(title) == 0;
});

try {
musicBrainz.albumId = releases[0]['id'][0];
bim.hello = true;
}
catch { };
trackLogger.log(`| \u27a4 AlbumId: ${musicBrainz.albumId}`);
try {
musicBrainz.albumArtistId = releases[0]['artist-credit'][0]['name-credit'][0]['artist'][0]['id'][0];
} catch { };
trackLogger.log(`| \u27a4 AlbumArtistId: ${musicBrainz.albumArtistId}`);
});
} catch (error) {
trackLogger.log(error);
}
//
}).catch(error => {
trackLogger.write(`[failed, ${error.message}]\n`);
});
}
return musicBrainz;
const got = require('got');
const {parseStringPromise: xml2js} = require('xml2js');

class MusicBrainzError extends Error {
constructor(message, statusCode) {
super(message);
if (statusCode) this.statusCode = statusCode;
}
}

async function query(entity_type, entity, args) {
let response = await got(`https://musicbrainz.org/ws/2/${entity_type}/${entity}?inc=artists+releases+discids`, {
searchParams: {...args, ...('inc' in args ? {inc: args.inc.join('+')} : {}), ...(args.json ? {fmt: 'json'} : {})},
});
let body;
try {
body = response.body.startsWith('<?xml')
? await xml2js(response.body, {trim: true, mergeAttrs: true, explicitRoot: false, explicitArray: false})
: JSON.parse(response.body);
} catch {
throw new MusicBrainzError('Invalid Server Response');
}
if (response.statusCode !== 200) {
throw new MusicBrainzError(body.error || 'An error occurred', response.statusCode);
}
return body;
}

module.exports = {
gatherMusicBrainzMetadata,
async function lookupISRC(isrc, storefront) {
let {
recording: {
id: trackId,
'release-list': {release: releases},
},
} = (await query('isrc', isrc, {inc: ['releases']})).isrc['recording-list'];
releases = Array.isArray(releases) ? releases : [releases];

let {id: releaseId} = releases.find(release => release.country === storefront) || releases[0];

let release = await query('release', releaseId, {inc: ['artists', 'release-groups', 'media'], json: true});

let {artist: artistMeta} = release['artist-credit'][0];
return {
trackId,
releaseId,
artistId: artistMeta.id,
artistSortOrder: artistMeta['sort-name'],
releaseGroupId: release['release-group'].id,
releaseType: release['release-group']['primary-type'],
barcode: release.barcode,
releaseStatus: release.status.toLowerCase(),
script: release['text-representation'].script,
media: release.media[0].format,
};

}

module.exports = {lookupISRC};

0 comments on commit 1506d8e

Please sign in to comment.