diff --git a/.gitignore b/.gitignore
index 1266766..fff86a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,5 +129,4 @@ dist
.yarn/install-state.gz
.pnp.*
-# Miscellaneous
*.mp3
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a1..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml
deleted file mode 100644
index d1e3d40..0000000
--- a/.idea/git_toolbox_prj.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace-LifeIsARace.xml b/.idea/workspace-LifeIsARace.xml
deleted file mode 100644
index ec27889..0000000
--- a/.idea/workspace-LifeIsARace.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- "lastFilter": {
- "state": "OPEN",
- "assignee": "xtrll"
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- "associatedIndex": 4
-}
-
-
-
-
-
-
-
-
- {
- "keyToString": {
- "ASKED_ADD_EXTERNAL_FILES": "true",
- "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "Node.js.app.js.executor": "Run",
- "Node.js.audioController.js.executor": "Run",
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "git-widget-placeholder": "main",
- "ignore.virus.scanning.warn.message": "true",
- "javascript.nodejs.core.library.configured.version": "21.6.2",
- "javascript.nodejs.core.library.typings.version": "20.12.7",
- "last_opened_file_path": "C:/Users/XTRLL/OneDrive/Projects/WebstormProjects/MusicMetaFinder",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "settings.editor.selected.configurable": "terminal",
- "vue.rearranger.settings.migration": "true"
- }
-}
-
-
-
-
-
-
-
-
-
- 1713646863779
-
-
- 1713646863779
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app.js b/cli.js
similarity index 63%
rename from app.js
rename to cli.js
index f0fc03b..cc54c90 100644
--- a/app.js
+++ b/cli.js
@@ -1,34 +1,36 @@
#!/usr/bin/env node
-import { checkEnvVariables } from './src/services/checkEnvVariables.js';
-import { checkInputPath } from './src/services/checkInputPath.js';
-import fetchFiles from './src/utils/filesFetcher.js';
-import { validateAudioFiles } from './src/controllers/fileController.js';
-import { recognizeAudioFiles } from './src/controllers/recognitionController.js';
-import { retrieveMetadata } from './src/controllers/metadataController.js';
+import checkEnvVariables from './src/utils/checkEnvVariables.js';
+import checkInputPath from './src/utils/checkInputPath.js';
+import fetchFiles from './src/utils/fetchFiles.js';
+import validateAudioFiles from './src/services/fileService.js';
+import recognizeAudioFiles from './src/services/musicRecognitionService.js';
+import retrieveMetadata from './src/services/metadataRetrievalService.js';
const { ACOUSTID_API_KEY, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET } = process.env;
async function main() {
try {
// Check for required environment variables
- checkEnvVariables();
- // Check for the input path
+ // checkEnvVariables();
+ // Check for required input path
const inputPath = process.argv[[2]];
checkInputPath(inputPath);
+ // Preferred service can be provided
+ const service = process.argv[[3]] || undefined;
// Resolve the input path to get array of file paths (handles one or more files)
const files = await fetchFiles(inputPath);
// Process the resolved paths to confirm and prepare the audio file for metadata recognition
const audioFiles = await validateAudioFiles(files);
// Recognize the content of the audio file and obtain the corresponding Spotify track ID
- const recordingIds = await recognizeAudioFiles(audioFiles);
+ const audioIds = await recognizeAudioFiles(audioFiles, service);
// Fetch the audio metadata from Spotify using the recognized track IDs
- const audioMetadata = await retrieveMetadata(recordingIds);
+ const audioMetadata = await retrieveMetadata(audioIds, service);
console.log(audioMetadata);
// Write the fetched metadata into the audio file
// const processedAudioFiles = await fileController.writeMetadata(audioMetadata, audioFiles);
} catch (e) {
- console.error('An error occurred inside app.js:', e);
+ console.error('An error occurred inside cli.js:', e);
process.exit(1);
}
}
diff --git a/package-lock.json b/package-lock.json
index 95865c0..4b237eb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,14 +10,17 @@
"dependencies": {
"axios": "^1.6.8",
"axios-retry": "^4.1.0",
- "command-exists": "^1.2.9",
+ "commander": "^12.0.0",
"dotenv": "^16.4.5",
+ "fluent-ffmpeg": "^2.1.2",
"fpcalc": "^1.3.0",
"music-metadata": "^7.14.0",
+ "node-fetch": "^3.3.2",
+ "node-id3": "^0.2.6",
"qs": "^6.12.1"
},
"bin": {
- "analyze-audio": "node --env-file .env ./app.js"
+ "analyze-audio": "node --env-file .env ./cli.js"
},
"devDependencies": {
"@eslint/eslintrc": "^3.0.2",
@@ -383,6 +386,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/async": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
+ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -517,10 +525,13 @@
"node": ">= 0.8"
}
},
- "node_modules/command-exists": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
- "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
+ "node_modules/commander": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
+ "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/concat-map": {
"version": "0.0.1",
@@ -607,6 +618,14 @@
"node": ">= 8"
}
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/data-view-buffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
@@ -1268,6 +1287,28 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -1332,6 +1373,29 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
+ "node_modules/fluent-ffmpeg": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz",
+ "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==",
+ "dependencies": {
+ "async": ">=0.2.9",
+ "which": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/fluent-ffmpeg/node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
@@ -1373,6 +1437,17 @@
"node": ">= 6"
}
},
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/fpcalc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fpcalc/-/fpcalc-1.3.0.tgz",
@@ -1619,6 +1694,17 @@
"node": ">= 0.4"
}
},
+ "node_modules/iconv-lite": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
+ "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -1964,8 +2050,7 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/js-yaml": {
"version": "4.1.0",
@@ -2137,6 +2222,49 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
+ "node_modules/node-id3": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/node-id3/-/node-id3-0.2.6.tgz",
+ "integrity": "sha512-w8GuKXLlPpDjTxLowCt/uYMhRQzED3cg2GdSG1i6RSGKeDzPvxlXeLQuQInKljahPZ0aDnmyX7FX8BbJOM7REg==",
+ "dependencies": {
+ "iconv-lite": "0.6.2"
+ }
+ },
"node_modules/object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -2600,6 +2728,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -3014,6 +3147,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
+ "node_modules/web-streams-polyfill": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index fb0e3db..e0bc110 100644
--- a/package.json
+++ b/package.json
@@ -3,15 +3,18 @@
"version": "1.0.0",
"description": "CLI utility for music enthusiasts to automatically recognize tracks and enrich file metadata based on the fetched information.",
"bin": {
- "analyze-audio": "node --env-file .env ./app.js"
+ "analyze-audio": "node --env-file .env ./cli.js"
},
"dependencies": {
"axios": "^1.6.8",
"axios-retry": "^4.1.0",
- "command-exists": "^1.2.9",
+ "commander": "^12.0.0",
"dotenv": "^16.4.5",
+ "fluent-ffmpeg": "^2.1.2",
"fpcalc": "^1.3.0",
"music-metadata": "^7.14.0",
+ "node-fetch": "^3.3.2",
+ "node-id3": "^0.2.6",
"qs": "^6.12.1"
},
"devDependencies": {
@@ -24,7 +27,7 @@
},
"scripts": {
"lint": "eslint . --fix",
- "analyze": "node --env-file .env app.js"
+ "analyze": "node --env-file .env cli.js"
},
"type": "module"
}
diff --git a/src/controllers/metadataController.js b/src/adapters/metadata/musicBrainzAdapter.js
similarity index 58%
rename from src/controllers/metadataController.js
rename to src/adapters/metadata/musicBrainzAdapter.js
index e02b08c..776fdd2 100644
--- a/src/controllers/metadataController.js
+++ b/src/adapters/metadata/musicBrainzAdapter.js
@@ -1,22 +1,22 @@
-import getTrackMetadata from '../api/metadataRetrieval.js';
-import getLyrics from '../api/lyricRetrieval.js';
-import {getAlbumArt} from "../api/imageRetrieval.js";
+import requestMetadata from '../../api/metadata/musicBrainzApi.js';
+import getAlbumArt from "../../api/metadata/coverArtArchiveApi.js";
+import getLyrics from '../../api/metadata/lyricOvhApi.js';
/**
- * Controller to handle retrieval of metadata for an array of MusicBrainz recording IDs.
+ * Adapter to handle retrieval of metadata for an array of MusicBrainz recording IDs.
* @function
* @param {string[]} recordingIds - An array of MusicBrainz recording IDs.
- * @returns {Promise