Compare commits
No commits in common. "master" and "v1.0.8" have entirely different histories.
|
@ -1,3 +0,0 @@
|
|||
github: captn3m0
|
||||
ko_fi: captn3m0
|
||||
liberapay: captn3m0
|
|
@ -4,7 +4,7 @@ jobs:
|
|||
tests:
|
||||
strategy:
|
||||
matrix:
|
||||
node: ["18", "20", "21"]
|
||||
node: ["16", "14", "12"]
|
||||
name: Run NPM Stuff
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -7,16 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
## 1.0.9
|
||||
### Changed
|
||||
- Dependency Updates
|
||||
- Minimum NodeJS version is now v14
|
||||
|
||||
## 1.0.8
|
||||
### Added
|
||||
- Dependency Updates
|
||||
|
||||
## 1.0.7
|
||||
### Added
|
||||
- `--version` is now supported
|
||||
- An update notification is shown if the package isn't latest.
|
||||
|
|
|
@ -52,12 +52,14 @@ You need to pass 2 parameters, a Youtube URL and a output CUE filename. YouTube
|
|||
very specific edge cases, they should not be required for most files.
|
||||
|
||||
Examples
|
||||
$ youtube-cue --audio-file audio.m4a "https://www.youtube.com/watch?v=WzpmVxvoBoc" "The Groovy Nobody - Solarium.cue"
|
||||
"The Groovy Nobody - Solarium.cue" saved
|
||||
$ youtube-cue --audio-file audio.m4a "https://www.youtube.com/watch?v=THzUassmQwE"
|
||||
"T A Y L O R S W I F T – Folklore [Full album].cue" saved
|
||||
$ youtube-cue "https://youtu.be/THzUassmQwE" folklore.cue
|
||||
folklore.cue saved
|
||||
|
||||
## Personal Usage
|
||||
|
||||
I have this in my `.bashrc` to download, split, tag, and import albums using beet:
|
||||
I have this in my `.bashrc` to download, split, tag, and import albums:
|
||||
|
||||
```shell
|
||||
function ytdl.album() {
|
||||
|
|
1
index.js
1
index.js
|
@ -74,7 +74,6 @@ if (argv.version) {
|
|||
artist,
|
||||
forceTimestamps,
|
||||
forceDurations,
|
||||
length: Number(info.videoDetails.lengthSeconds),
|
||||
});
|
||||
generate({ tracks, artist, audioFile, album }, output_file);
|
||||
console.log(`"${output_file}" saved`);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "youtube-cue",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.8",
|
||||
"description": "Generates Cue sheet from Youtube URL",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -11,15 +11,15 @@
|
|||
"author": "Nemo <npm@captnemo.in>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"mocha": "^10.0.0",
|
||||
"prettier": "^3.1.0"
|
||||
"mocha": "^9.2.0",
|
||||
"prettier": "^2.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"console-log-level": "^1.4.1",
|
||||
"get-artist-title": "^1.3.1",
|
||||
"minimist": "^1.2.8",
|
||||
"update-notifier": "^7.0.0",
|
||||
"ytdl-core": "^4.11.5"
|
||||
"minimist": "^1.2.5",
|
||||
"update-notifier": "^5.1.0",
|
||||
"ytdl-core": "^4.8.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
13
src/cue.js
13
src/cue.js
|
@ -1,10 +1,5 @@
|
|||
import fs from "fs";
|
||||
|
||||
/** code to create a new CUE file, as per the standard
|
||||
* with a REM PERFORMER, TITLE, FILE attribute
|
||||
* and a list of tracks provided as input
|
||||
*/
|
||||
|
||||
// https://en.wikipedia.org/wiki/Cue_sheet_(computing)
|
||||
export function generate(data, outputFile) {
|
||||
try {
|
||||
|
@ -16,12 +11,14 @@ export function generate(data, outputFile) {
|
|||
fs.appendFileSync(outputFile, `FILE "${data.audioFile}" M4A\n`);
|
||||
for (var i in data.tracks) {
|
||||
let song = data.tracks[i];
|
||||
let minutes = String(song.start.hh * 60 + song.start.mm).padStart(2, "0");
|
||||
let seconds = String(song.start.ss).padStart(2, "0");
|
||||
let minutes = song.start.hh * 60 + song.start.mm;
|
||||
fs.appendFileSync(outputFile, ` TRACK ${song.track} AUDIO\n`);
|
||||
fs.appendFileSync(outputFile, ` TITLE "${song.title}"\n`);
|
||||
fs.appendFileSync(outputFile, ` PERFORMER "${song.artist}"\n`);
|
||||
// Cue File is always MINUTES:SECONDS:FRAME, where FRAME is 00
|
||||
fs.appendFileSync(outputFile, ` INDEX 01 ${minutes}:${seconds}:00\n`);
|
||||
fs.appendFileSync(
|
||||
outputFile,
|
||||
` INDEX 01 ${minutes}:${song.start.ss}:00\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ var firstPass = function (line) {
|
|||
let track = matches.groups["trackl"]
|
||||
? +matches.groups["trackl"]
|
||||
: matches.groups["trackr"]
|
||||
? +matches.groups["trackr"]
|
||||
: null;
|
||||
? +matches.groups["trackr"]
|
||||
: null;
|
||||
return {
|
||||
track: track,
|
||||
start: {
|
||||
|
@ -153,19 +153,9 @@ var fixDurations = function (list) {
|
|||
}
|
||||
};
|
||||
|
||||
var dropInvalid = function (e) {
|
||||
// All tracks should start before the closing time
|
||||
if (_options.length) return e.start.calc < _options.length;
|
||||
return true;
|
||||
};
|
||||
|
||||
export function parse(
|
||||
text,
|
||||
options = {
|
||||
artist: "Unknown",
|
||||
forceTimestamps: false,
|
||||
forceDurations: false,
|
||||
},
|
||||
options = { artist: "Unknown", forceTimestamps: false, forceDurations: false }
|
||||
) {
|
||||
_options = options;
|
||||
let durations = false;
|
||||
|
@ -194,10 +184,5 @@ export function parse(
|
|||
}
|
||||
}
|
||||
|
||||
return result
|
||||
.map(parseTitle)
|
||||
.map(parseArtist)
|
||||
.map(addTrack)
|
||||
.map(addEnd)
|
||||
.filter(dropInvalid);
|
||||
return result.map(parseTitle).map(parseArtist).map(addTrack).map(addEnd);
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*jshint esversion: 6 */
|
||||
import { strict as assert } from "assert";
|
||||
import { generate } from "../src/cue.js";
|
||||
import fs from "fs";
|
||||
|
||||
const DATA = {
|
||||
artist: "Dumbledore",
|
||||
album: "Curse of the Elder Wand",
|
||||
audioFile: "audio.m4a",
|
||||
tracks: [
|
||||
{
|
||||
artist: "Unknown",
|
||||
title: "the 1",
|
||||
track: 1,
|
||||
start: { ts: "00:00:00", hh: 0, mm: 0, ss: 0, calc: 0 },
|
||||
end: { ts: "00:3:9", hh: 0, mm: 3, ss: 9, calc: 189 },
|
||||
_: { left_text: "", right_text: "the 1" },
|
||||
},
|
||||
{
|
||||
artist: "Unknown",
|
||||
title: "cardigan",
|
||||
track: 2,
|
||||
start: { ts: "00:3:09", hh: 0, mm: 3, ss: 9, calc: 189 },
|
||||
end: { ts: "00:9:30", hh: 0, mm: 9, ss: 30, calc: 570 },
|
||||
_: { left_text: "", right_text: "cardigan" },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe("CUE", function () {
|
||||
it("should generate with leading zeroes", function () {
|
||||
generate(DATA, "/tmp/test.cue");
|
||||
const CUE_EXPECTED = `REM Generated using youtube-cue
|
||||
PERFORMER "Dumbledore"
|
||||
TITLE "Curse of the Elder Wand"
|
||||
FILE "audio.m4a" M4A
|
||||
TRACK 1 AUDIO
|
||||
TITLE "the 1"
|
||||
PERFORMER "Unknown"
|
||||
INDEX 01 00:00:00
|
||||
TRACK 2 AUDIO
|
||||
TITLE "cardigan"
|
||||
PERFORMER "Unknown"
|
||||
INDEX 01 03:09:00
|
||||
`;
|
||||
assert.equal(CUE_EXPECTED, fs.readFileSync("/tmp/test.cue", "utf-8"));
|
||||
});
|
||||
});
|
|
@ -152,7 +152,7 @@ describe("Parser", function () {
|
|||
let result = parse(
|
||||
`1. Artist - Title 5:00
|
||||
2. Another Artist - Another Title 4:20`,
|
||||
{ forceTimestamps: true },
|
||||
{ forceTimestamps: true }
|
||||
);
|
||||
assert.deepEqual(result[0].end, {
|
||||
ts: "00:4:20",
|
||||
|
@ -174,7 +174,7 @@ describe("Parser", function () {
|
|||
let result = parse(
|
||||
`1. Artist - Title 1:00
|
||||
2. Another Artist - Another Title 1:15`,
|
||||
{ forceDurations: true },
|
||||
{ forceDurations: true }
|
||||
);
|
||||
assert.deepEqual(result[0], {
|
||||
track: 1,
|
||||
|
|
Loading…
Reference in New Issue