This commit is contained in:
installgen2 2019-06-22 05:47:25 -07:00
commit 4ac138b4ab
7 changed files with 336 additions and 0 deletions

12
.editorconfig Normal file
View 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
View File

@ -0,0 +1,3 @@
{
"extends" : "@edenjs/eden"
}

22
.gitattributes vendored Normal file
View 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
View 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
View 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
View 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
View 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"
}
}