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