a
This commit is contained in:
commit
4ac138b4ab
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{bat,cmd}]
|
||||||
|
end_of_line = crlf
|
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends" : "@edenjs/eden"
|
||||||
|
}
|
22
.gitattributes
vendored
Normal file
22
.gitattributes
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Automatically normalize line endings for all text-based files
|
||||||
|
# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# For the following file types, normalize line endings to LF on
|
||||||
|
# checkin and prevent conversion to CRLF when they are checked out
|
||||||
|
# (this is required in order to prevent newline related issues like,
|
||||||
|
# for example, after the build script is run)
|
||||||
|
.* text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.jade text eol=lf
|
||||||
|
*.js text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.less text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.txt text eol=lf
|
||||||
|
*.xml text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Debug log from npm
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Error log from yarn
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# yarn lock - do work pls
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# nodejs modules
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# edenjs stuff
|
||||||
|
data/
|
||||||
|
config.js
|
||||||
|
edenappconfig.js
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea
|
||||||
|
.remote-sync.json
|
||||||
|
|
||||||
|
# Log and Sentry
|
||||||
|
*.log
|
||||||
|
*.sentry
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
*.rdb
|
||||||
|
|
||||||
|
# sqlite files
|
||||||
|
*.db
|
||||||
|
*.sdb
|
||||||
|
*.sqlite
|
||||||
|
*.db3
|
||||||
|
*.s3db
|
||||||
|
*.sqlite3
|
||||||
|
*.sl3
|
||||||
|
*.db2
|
||||||
|
*.s2db
|
||||||
|
*.sqlite2
|
||||||
|
*.sl2
|
||||||
|
|
||||||
|
# Other junk
|
||||||
|
.*.swp
|
||||||
|
._*
|
||||||
|
.DS_Store
|
||||||
|
.hg
|
||||||
|
.npmrc
|
||||||
|
.lock-wscript
|
||||||
|
.svn
|
||||||
|
.wafpickle-*
|
||||||
|
config.gypi
|
||||||
|
CVS
|
161
index.js
Normal file
161
index.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const tmp = require('tmp-promise');
|
||||||
|
const os = require('os');
|
||||||
|
const shitExec = require('child_process').exec;
|
||||||
|
const Path = require('path');
|
||||||
|
|
||||||
|
async function exec(...args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
shitExec(...args, (error, stdout) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve(stdout.trim());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
if (!process.argv[2]) {
|
||||||
|
console.log('need a video');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [pAlbum, pArtist, pTitle] = (process.argv.length >= 3 ? process.argv.slice(3).join(' ').trim().match(/^([^/]+)(?:\/([^/]+)(?:\/([^/]+))?)?$/) || [] : []).slice(1).map((item) => {
|
||||||
|
return item ? item.trim() : item;
|
||||||
|
});
|
||||||
|
|
||||||
|
const dir = await tmp.dir({ prefix : 'mudl_', unsafeCleanup : true });
|
||||||
|
|
||||||
|
let files = [];
|
||||||
|
let inputType = null;
|
||||||
|
|
||||||
|
if (['/', '~', '.'].includes(process.argv[2][0])) {
|
||||||
|
console.log('got a str8 filename');
|
||||||
|
|
||||||
|
inputType = 'file';
|
||||||
|
|
||||||
|
files = [{
|
||||||
|
image : null,
|
||||||
|
file : process.argv[2],
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
console.log('got a link');
|
||||||
|
inputType = 'url';
|
||||||
|
|
||||||
|
console.log(`Temporarily saving to ${dir.path}`);
|
||||||
|
await exec(`youtube-dl --write-thumbnail -f bestaudio -x -o "${dir.path}/[%(album)s] -- [%(artist)s] -- [%(track_number)s] -- [%(track)s] -- [%(title)s].%(ext)s" ${process.argv[2]}`);
|
||||||
|
console.log('Done saving');
|
||||||
|
|
||||||
|
const filesList = await fs.readdir(dir.path);
|
||||||
|
|
||||||
|
files = filesList.map((rawFilePath) => {
|
||||||
|
const filePath = Path.parse(rawFilePath);
|
||||||
|
|
||||||
|
if (['.png', '.jpg'].includes(filePath.ext)) return null;
|
||||||
|
|
||||||
|
const rawImagePath = filesList.find((rawP) => {
|
||||||
|
const p = Path.parse(rawP);
|
||||||
|
return ['.png', '.jpg'].includes(p.ext) && p.name === filePath.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
let album = pAlbum || null;
|
||||||
|
let artist = pArtist || null;
|
||||||
|
let title = pTitle || null;
|
||||||
|
let trackNum = null;
|
||||||
|
|
||||||
|
let rawTitle = null;
|
||||||
|
|
||||||
|
const fullMatch = rawFilePath.match(/^\[(.*?)\] -- \[(.*?)\] -- \[(.*?)\] -- \[(.*?)\] -- \[(.*?)\]\..*?$/);
|
||||||
|
|
||||||
|
if (fullMatch !== null) {
|
||||||
|
const [yAlbum, yArtist, yTrackNum, yTitle, yRawTitle] = fullMatch.slice(1)
|
||||||
|
.map(item => (item === 'NA' ? null : item))
|
||||||
|
.map(item => (item !== null ? item.trim() : null))
|
||||||
|
.map(item => (item !== null ? item.replace(/(^|\s+)(.)_($|\s+)/g, '$1$2$3') : null));
|
||||||
|
|
||||||
|
if (yAlbum && !album) album = yAlbum;
|
||||||
|
if (yArtist && !artist) artist = yArtist;
|
||||||
|
if (yTitle && !title) title = yTitle;
|
||||||
|
if (yTrackNum && !trackNum) trackNum = yTrackNum;
|
||||||
|
if (yRawTitle && !rawTitle) rawTitle = yRawTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (artist === null && title === null) {
|
||||||
|
const rawTitleMatch = rawTitle.match(/^([^-]+)(?:\s*-\s*(.+))?$/);
|
||||||
|
|
||||||
|
if (rawTitleMatch[2] !== undefined && rawTitleMatch[2] !== null) {
|
||||||
|
[artist, title] = rawTitleMatch.slice(1).map(item => (item ? item.trim() : item));
|
||||||
|
} else {
|
||||||
|
title = rawTitleMatch[1].trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (album === null) album = 'Unknown';
|
||||||
|
if (artist === null) artist = 'Unknown';
|
||||||
|
if (title === null) title = 'Unknown';
|
||||||
|
|
||||||
|
return {
|
||||||
|
file : Path.join(dir.path, rawFilePath),
|
||||||
|
image : Path.join(dir.path, rawImagePath),
|
||||||
|
album,
|
||||||
|
artist,
|
||||||
|
title,
|
||||||
|
};
|
||||||
|
}).filter(p => p !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
album, artist, title, trackNum, file, image,
|
||||||
|
} of files) {
|
||||||
|
const path = `${os.homedir()}/Music/${album}/${artist} - ${title}.mp3`;
|
||||||
|
await fs.ensureDir(`${os.homedir()}/Music/${album}`);
|
||||||
|
|
||||||
|
if (!(await fs.exists(path))) {
|
||||||
|
console.log(`Encoding to: ${path}`);
|
||||||
|
if (image) {
|
||||||
|
await exec(`ffmpeg -i "${file}" -i "${image}" -map 0:0 -map 1:0 -id3v2_version 4 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" "${path}"`);
|
||||||
|
} else {
|
||||||
|
await exec(`ffmpeg -i "${file}" -id3v2_version 4 "${path}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Adding id3v2 tags');
|
||||||
|
|
||||||
|
const tagArgs = [];
|
||||||
|
|
||||||
|
tagArgs.push(['--artist', artist || 'Unknown']);
|
||||||
|
tagArgs.push(['--album', album || 'Unknown']);
|
||||||
|
tagArgs.push(['--song', title || 'Unknown']);
|
||||||
|
if (inputType === 'url') tagArgs.push(['--comment', process.argv[2]]);
|
||||||
|
if (trackNum) tagArgs.push(['--track', trackNum]);
|
||||||
|
|
||||||
|
const tagArgsString = tagArgs.map(([tag, val]) => `${tag} "${val}"`).join(' ');
|
||||||
|
await exec(`id3v2 ${tagArgsString} "${path}"`);
|
||||||
|
|
||||||
|
if (await fs.exists(Path.join(os.homedir(), '.tmsu'))) {
|
||||||
|
console.log('adding tmsu tags');
|
||||||
|
|
||||||
|
const fsTagArgs = [];
|
||||||
|
|
||||||
|
if (artist) fsTagArgs.push(['artist', artist]);
|
||||||
|
if (album) fsTagArgs.push(['album', album]);
|
||||||
|
|
||||||
|
if (fsTagArgs.length > 0) {
|
||||||
|
const fsTagArgsString = fsTagArgs.map(([tag, val]) => `"${tag}=${val}"`).join(' ');
|
||||||
|
await exec(`tmsu tag "${path}" ${fsTagArgsString}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Finished: ${album}/${artist} - ${title}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Finished everything, cleaning up...');
|
||||||
|
await dir.cleanup();
|
||||||
|
console.log('Done!');
|
||||||
|
})();
|
63
package-lock.json
generated
Normal file
63
package-lock.json
generated
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"name": "mudl",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": {
|
||||||
|
"version": "3.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz",
|
||||||
|
"integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw=="
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"jsonfile": "^4.0.0",
|
||||||
|
"universalify": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"graceful-fs": {
|
||||||
|
"version": "4.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
|
||||||
|
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"os-tmpdir": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||||
|
},
|
||||||
|
"tmp": {
|
||||||
|
"version": "0.0.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
|
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||||
|
"requires": {
|
||||||
|
"os-tmpdir": "~1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tmp-promise": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-hOabTz9Tp49wCozFwuJe5ISrOqkECm6kzw66XTP23DuzNU7QS/KiZq5LC9Y7QSy8f1rPSLy4bKaViP0OwGI1cA==",
|
||||||
|
"requires": {
|
||||||
|
"bluebird": "^3.5.0",
|
||||||
|
"tmp": "0.0.33"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"universalify": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
package.json
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "mudl",
|
||||||
|
"description": "nothing yet",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"dependencies": {
|
||||||
|
"fs-extra": "^7.0.1",
|
||||||
|
"tmp-promise": "^1.0.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"mudl" : "index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"@edenjs/eslint-config-eden": "^2.0.14",
|
||||||
|
"eslint-config-airbnb": "^17.1.0",
|
||||||
|
"eslint-plugin-import": "^2.16.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||||
|
"eslint-plugin-react": "^7.12.4"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user