diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..455bc8d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Organise", + "args": ["${workspaceFolder}/src/cli.js", "organise", "test", "out"], + "console": "integratedTerminal", + "skipFiles": [ + "${workspaceRoot}/node_modules/**/*.js", + "/**/*.js" + ], + "env": { + "DEBUG": "publikator:*", + "DEBUG_COLORS": "1" + } + } + ] +} diff --git a/package.json b/package.json index 8af58be..79e512b 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "publikator", - "version": "0.1.0", + "version": "0.2.0", "main": "index.js", "repository": "https://github.com/aengl/publikator.git", "author": "Lynn Smeria ", - "license": "MIT", + "license": "Unlicense", "bin": { "publikator": "publikator.js" }, @@ -16,8 +16,8 @@ "debug": "3.1.0", "fs-extra": "7.0.0", "js-yaml": "3.12.0", - "jsmediatags": "3.8.1", "lodash": "4.17.10", + "music-metadata": "2.6.0", "sanitize-filename": "1.6.1", "walkdir": "0.0.12" }, diff --git a/src/generate.js b/src/generate.js index 73b4df8..92bf61a 100644 --- a/src/generate.js +++ b/src/generate.js @@ -18,17 +18,10 @@ module.exports = { 'track-count': tracks.length, tracks: tracks.map((track, i) => ({ path: track.path, - size: track.size, position: i, - ...tags.getTags(track, [ - 'title', - 'artist', - 'album', - 'year', - 'comment', - 'track', - 'genre', - ]), + common: track.common, + format: track.format, + ...tags.getTags(track, ['foo']), })), }; }) diff --git a/src/organise.js b/src/organise.js index fee68ad..8e88a91 100644 --- a/src/organise.js +++ b/src/organise.js @@ -5,9 +5,10 @@ const sanitize = require('sanitize-filename'); const debug = require('debug')('publikator:organise'); const tags = require('./tags'); -const getFolderName = file => `${file.tags.artist} - ${file.tags.album}`; +const getArtists = file => file.common.artist || file.common.artists.join(', '); +const getFolderName = file => `${getArtists(file)} - ${file.common.album}`; const getFileName = file => - `${file.tags.track} - ${file.tags.title}${path.extname(file.path)}`; + `${file.common.track.no} - ${file.common.title}${path.extname(file.path)}`; module.exports = { /** @@ -22,7 +23,12 @@ module.exports = { */ byAlbum: async (root, taggedFiles) => { const files = taggedFiles.filter(file => - tags.hasTags(file, ['artist', 'album', 'track', 'title']) + tags.hasTags(file, [ + 'common.artists', + 'common.album', + 'common.track', + 'common.title', + ]) ); debug(`grouping tracks by album`); diff --git a/src/scan.js b/src/scan.js index 00bf14c..56b3510 100644 --- a/src/scan.js +++ b/src/scan.js @@ -22,7 +22,7 @@ module.exports = { /** * Reads ID3 tags from all files and returns an array in the form of: - * [{ path, size, tags }, ...] + * [{ path, common, format, native }, ...] */ readTags: files => { debug(`reading tags from ${files.length} file(s)`); @@ -31,8 +31,7 @@ module.exports = { const info = await tags.readTags(file); return { path: file, - size: info.size, - tags: info.tags, + ...info, }; }) ); diff --git a/src/tags.js b/src/tags.js index b4292c8..6bf4a3e 100644 --- a/src/tags.js +++ b/src/tags.js @@ -1,4 +1,5 @@ -const jsmediatags = require('jsmediatags'); +const _ = require('lodash'); +const mm = require('music-metadata'); const debug = require('debug')('publikator:tags'); module.exports = { @@ -6,24 +7,17 @@ module.exports = { * Reads tags from a track. */ readTags: file => - new Promise((resolve, reject) => { - jsmediatags.read(file, { - onSuccess: info => { - resolve(info); - }, - onError: error => { - debug(error.type); - debug(error.info); - reject(error); - }, - }); + mm.parseFile(file, { + duration: true, + native: true, + skipCovers: false, }), /** * Returns true if a file has all required tags. */ hasTags: (taggedFile, tags) => { - if (tags.some(tag => taggedFile.tags[tag] === undefined)) { + if (tags.some(tag => _.get(taggedFile, tag) === undefined)) { debug(`track'${taggedFile.path}' is missing one or more required tags`); return false; } @@ -35,8 +29,9 @@ module.exports = { */ getTags: (taggedFile, tags) => tags.reduce((all, tag) => { - if (taggedFile.tags[tag] !== undefined) { - all[tag] = taggedFile.tags[tag]; // eslint-disable-line + const value = _.get(taggedFile, tag); + if (value !== undefined) { + all[tag] = value; // eslint-disable-line } return all; }, {}), diff --git a/yarn.lock b/yarn.lock index a6df36e..7019418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,13 +21,13 @@ ajv-keywords@^3.0.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" ajv@^6.0.1, ajv@^6.5.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" + version "6.5.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" - uri-js "^4.2.1" + uri-js "^4.2.2" ansi-align@^2.0.0: version "2.0.0" @@ -150,8 +150,8 @@ async@~1.0.0: resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" atob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" axobject-query@^2.0.1: version "2.0.1" @@ -326,9 +326,9 @@ chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -ci-info@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.2.0.tgz#8d1e9cb4051482ff70cd52a89b4b095a8fb635f6" +ci-info@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.4.0.tgz#4841d53cad49f11b827b648ebde27a6e189b412f" circular-json@^0.3.1: version "0.3.3" @@ -510,11 +510,10 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" + object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" @@ -610,6 +609,10 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" +es6-promise@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -886,6 +889,10 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +file-type@9: + version "9.0.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -921,10 +928,6 @@ for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -1234,10 +1237,10 @@ is-callable@^1.1.1, is-callable@^1.1.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" is-ci@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.0.tgz#3f4a08d6303a09882cef3f0fb97439c5f5ce2d53" dependencies: - ci-info "^1.0.0" + ci-info "^1.3.0" is-data-descriptor@^0.1.4: version "0.1.4" @@ -1417,12 +1420,6 @@ js-yaml@3.12.0, js-yaml@^3.11.0: argparse "^1.0.7" esprima "^4.0.0" -jsmediatags@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/jsmediatags/-/jsmediatags-3.8.1.tgz#e27d26e957b0b330c28f9762c82940c4dcc64720" - dependencies: - xhr2 "^0.1.4" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -1567,6 +1564,10 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +media-typer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -1639,6 +1640,18 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +music-metadata@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/music-metadata/-/music-metadata-2.6.0.tgz#a913a3a1de73b965158c243a5e188be9ec901ff9" + dependencies: + debug "^3.1.0" + es6-promise "^4.2.4" + file-type "9" + media-typer "^0.3.0" + strtok3 "^1.5.3" + then-read-stream "^1.2.1" + token-types "^0.9.4" + mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" @@ -1791,7 +1804,7 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-keys@^1.0.11, object-keys@^1.0.8: +object-keys@^1.0.11, object-keys@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" @@ -2107,8 +2120,8 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" repeat-string@^1.6.1: version "1.6.1" @@ -2206,8 +2219,8 @@ semver-diff@^2.0.0: semver "^5.0.3" "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + version "5.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" set-blocking@~2.0.0: version "2.0.0" @@ -2417,13 +2430,22 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +strtok3@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-1.5.3.tgz#a788ce5b43cd5365d61ae9c7620113b2c94c068f" + dependencies: + debug "^3.1.0" + es6-promise "^4.2.4" + then-read-stream "^1.2.1" + token-types "^0.9.4" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" supports-color@^5.2.0, supports-color@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" dependencies: has-flag "^3.0.0" @@ -2477,6 +2499,12 @@ text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +then-read-stream@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/then-read-stream/-/then-read-stream-1.2.1.tgz#9baddcb8a4ebc8a6fb36436985d24c36f7908829" + dependencies: + es6-promise "^4.2.4" + through@2, through@^2.3.6, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -2519,6 +2547,10 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +token-types@^0.9.4: + version "0.9.4" + resolved "https://registry.yarnpkg.com/token-types/-/token-types-0.9.4.tgz#ea24c5c3fc577292a1d362a252e348a0016361ad" + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" @@ -2596,7 +2628,7 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" -uri-js@^4.2.1: +uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" dependencies: @@ -2690,10 +2722,6 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xhr2@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" - yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"