@makefully/dutifully 1.10.1 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -5
- package/LICENSE +21 -21
- package/README.md +216 -214
- package/cheer.js +36 -36
- package/package.json +63 -63
- package/say.js +15 -15
- package/src/classes/Cheer.js +254 -254
- package/src/classes/ElevenLabs.js +16 -16
- package/src/classes/FFMPEG.js +12 -12
- package/src/classes/LipSync.js +140 -132
- package/src/classes/Polly.js +9 -9
- package/src/classes/Rasterize.js +12 -12
- package/src/classes/TextToSpeech.js +215 -204
- package/src/classes/Transcript.js +72 -68
- package/src/classes/Transcription.js +169 -162
- package/src/formats/File.js +28 -26
- package/src/formats/JSONFile.js +41 -39
- package/src/formats/LRC.js +37 -37
- package/src/formats/MP3.js +61 -59
- package/src/formats/SAMI.js +58 -58
- package/src/formats/SRT.js +39 -39
- package/src/formats/VTT.js +37 -37
- package/src/helpers/dirs.js +30 -0
- package/src/helpers/getCaptions.js +43 -43
- package/src/helpers/getFileData.js +32 -32
- package/src/helpers/getJSON.js +32 -32
- package/src/index.js +58 -58
- package/src/say.js +141 -141
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const
|
|
2
|
-
TextToSpeech = require('./TextToSpeech');
|
|
3
|
-
|
|
4
|
-
module.exports = class ElevenLabs extends TextToSpeech {
|
|
5
|
-
constructor (data) {
|
|
6
|
-
const
|
|
7
|
-
{id, elevenLabsApiKey} = data.contents;
|
|
8
|
-
|
|
9
|
-
data.album = id;
|
|
10
|
-
data.encodedBy = 'ElevenLabs';
|
|
11
|
-
if (elevenLabsApiKey) {
|
|
12
|
-
data.config.apiKey = elevenLabsApiKey;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
super(data);
|
|
16
|
-
}
|
|
1
|
+
const
|
|
2
|
+
TextToSpeech = require('./TextToSpeech');
|
|
3
|
+
|
|
4
|
+
module.exports = class ElevenLabs extends TextToSpeech {
|
|
5
|
+
constructor (data) {
|
|
6
|
+
const
|
|
7
|
+
{id, elevenLabsApiKey} = data.contents;
|
|
8
|
+
|
|
9
|
+
data.album = id;
|
|
10
|
+
data.encodedBy = 'ElevenLabs';
|
|
11
|
+
if (elevenLabsApiKey) {
|
|
12
|
+
data.config.apiKey = elevenLabsApiKey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
super(data);
|
|
16
|
+
}
|
|
17
17
|
};
|
package/src/classes/FFMPEG.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const
|
|
2
|
-
Cheer = require('./Cheer'),
|
|
3
|
-
FFMPEG = class FFMPEG extends Cheer {
|
|
4
|
-
beforeSend (archive) {
|
|
5
|
-
const
|
|
6
|
-
{src} = this.config;
|
|
7
|
-
|
|
8
|
-
archive.directory(src, false);
|
|
9
|
-
super.beforeSend(archive);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
1
|
+
const
|
|
2
|
+
Cheer = require('./Cheer'),
|
|
3
|
+
FFMPEG = class FFMPEG extends Cheer {
|
|
4
|
+
beforeSend (archive) {
|
|
5
|
+
const
|
|
6
|
+
{src} = this.config;
|
|
7
|
+
|
|
8
|
+
archive.directory(src, false);
|
|
9
|
+
super.beforeSend(archive);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
13
|
module.exports = FFMPEG;
|
package/src/classes/LipSync.js
CHANGED
|
@@ -1,133 +1,141 @@
|
|
|
1
|
-
const
|
|
2
|
-
Cheer = require('./Cheer'),
|
|
3
|
-
fs = require('fs').promises,
|
|
4
|
-
getJSON = require('../helpers/getJSON'),
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
1
|
+
const
|
|
2
|
+
Cheer = require('./Cheer'),
|
|
3
|
+
fs = require('fs').promises,
|
|
4
|
+
getJSON = require('../helpers/getJSON'),
|
|
5
|
+
{ensureDir, ensureParentDir, readdirOrEmpty} = require('../helpers/dirs'),
|
|
6
|
+
id3 = require('node-id3').Promise,
|
|
7
|
+
filter = (fileType, file) => (file.indexOf('.') !== 0) && (file.slice(-(fileType.length + 1)) === `.${fileType}`),
|
|
8
|
+
combine = async (path, fileType) => {
|
|
9
|
+
const
|
|
10
|
+
files = (await readdirOrEmpty(path)).filter(filter.bind(null, fileType)),
|
|
11
|
+
list = [];
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < files.length; i++) {
|
|
14
|
+
const
|
|
15
|
+
file = files[i];
|
|
16
|
+
|
|
17
|
+
if (fileType === 'mp3') { // check id3 for lyrics presence.
|
|
18
|
+
const
|
|
19
|
+
{synchronisedLyrics} = await id3.read(`${path}${file}`);
|
|
20
|
+
|
|
21
|
+
if (synchronisedLyrics) {
|
|
22
|
+
const
|
|
23
|
+
index = synchronisedLyrics.map(({shortText}) => shortText).indexOf('lipsync');
|
|
24
|
+
|
|
25
|
+
if (index >= 0) {
|
|
26
|
+
list.push(file.substring(0, file.length - fileType.length - 1));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
list.push(file.substring(0, file.length - fileType.length - 1));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return list;
|
|
35
|
+
},
|
|
36
|
+
sortKeys = (obj) => Object.keys(obj).sort().reduce((s, key) => {
|
|
37
|
+
s[key] = obj[key];
|
|
38
|
+
return s;
|
|
39
|
+
}, {}),
|
|
40
|
+
mapReduction = (map, list) => list.reduce((obj, file) => {
|
|
41
|
+
const
|
|
42
|
+
id = file.substring(0, file.length - 4);
|
|
43
|
+
|
|
44
|
+
obj[id] = map[id];
|
|
45
|
+
return obj;
|
|
46
|
+
}, {}),
|
|
47
|
+
LipSync = class LipSync extends Cheer {
|
|
48
|
+
async prepare (data) {
|
|
49
|
+
this.differenceOnly = false;
|
|
50
|
+
this.updateList = null;
|
|
51
|
+
await this.replaceConfigPathWithJSON('script', 'files');
|
|
52
|
+
return super.prepare(data);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async checkDifference () {
|
|
56
|
+
const
|
|
57
|
+
{config} = this,
|
|
58
|
+
{files = {}, options = {}, output, src} = config,
|
|
59
|
+
{exportFormat = 'json', output: outputType = 'json'} = options,
|
|
60
|
+
file = 'mouthCues.json';
|
|
61
|
+
|
|
62
|
+
if (output) {
|
|
63
|
+
await ensureDir(output);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const
|
|
67
|
+
raw = outputType === 'json' && exportFormat !== 'mp3' ? await getJSON(`${output}${file}`) ?? {} : null,
|
|
68
|
+
alreadyLipSynced = raw ? Object.keys(raw) : await combine(output, exportFormat),
|
|
69
|
+
check = (id) => {
|
|
70
|
+
const
|
|
71
|
+
index = alreadyLipSynced.indexOf(id);
|
|
72
|
+
|
|
73
|
+
if (index >= 0) {
|
|
74
|
+
alreadyLipSynced.splice(index, 1);
|
|
75
|
+
return true;
|
|
76
|
+
} else {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
mergeLipSync = async (newLipSync = false) => { // Must run _after_ all checks and will remove what's left.
|
|
81
|
+
for (let i = 0; i < alreadyLipSynced.length; i++) {
|
|
82
|
+
const
|
|
83
|
+
key = alreadyLipSynced[i];
|
|
84
|
+
|
|
85
|
+
if (raw) {
|
|
86
|
+
delete raw[key];
|
|
87
|
+
} else {
|
|
88
|
+
await fs.rm(`${output}${key}.${exportFormat}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`Removed "${key}"`);
|
|
91
|
+
}
|
|
92
|
+
if (raw) {
|
|
93
|
+
await ensureParentDir(`${output}${file}`);
|
|
94
|
+
await fs.writeFile(`${output}${file}`, JSON.stringify(sortKeys({
|
|
95
|
+
...raw,
|
|
96
|
+
...newLipSync ? await getJSON(`${output}${file}`) ?? {} : {} // get new version.
|
|
97
|
+
}), null, 4));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return alreadyLipSynced.length;
|
|
101
|
+
},
|
|
102
|
+
list = (await readdirOrEmpty(src)).filter(filter.bind(null, 'mp3')).filter((file) => !check(file.substring(0, file.length - 4)));
|
|
103
|
+
|
|
104
|
+
this.differenceOnly = true;
|
|
105
|
+
|
|
106
|
+
if (list.length === 0) {
|
|
107
|
+
// We'll still run the merge in case any have been removed.
|
|
108
|
+
if (await mergeLipSync()) {
|
|
109
|
+
throw Error('Old lip-sync removed, but no new ones required generation.');
|
|
110
|
+
} else {
|
|
111
|
+
throw Error('Lip-sync already up to date.');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.updateList = list;
|
|
115
|
+
config.files = mapReduction(files, list);
|
|
116
|
+
this.mergeLipSync = mergeLipSync;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
beforeSend (archive) {
|
|
120
|
+
const
|
|
121
|
+
{src} = this.config;
|
|
122
|
+
|
|
123
|
+
if (this.differenceOnly) {
|
|
124
|
+
this.updateList.forEach((file) => archive.file(`${src}${file}`, {
|
|
125
|
+
name: file
|
|
126
|
+
}));
|
|
127
|
+
} else {
|
|
128
|
+
archive.directory(src, false);
|
|
129
|
+
}
|
|
130
|
+
super.beforeSend(archive);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
afterExport (...args) {
|
|
134
|
+
if (this.mergeLipSync) {
|
|
135
|
+
this.mergeLipSync(true);
|
|
136
|
+
}
|
|
137
|
+
super.afterExport(...args)
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
133
141
|
module.exports = LipSync;
|
package/src/classes/Polly.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const
|
|
2
|
-
TextToSpeech = require('./TextToSpeech');
|
|
3
|
-
|
|
4
|
-
module.exports = class Polly extends TextToSpeech {
|
|
5
|
-
constructor (data) {
|
|
6
|
-
data.album = data.contents.id;
|
|
7
|
-
data.encodedBy = 'Amazon Polly';
|
|
8
|
-
super(data);
|
|
9
|
-
}
|
|
1
|
+
const
|
|
2
|
+
TextToSpeech = require('./TextToSpeech');
|
|
3
|
+
|
|
4
|
+
module.exports = class Polly extends TextToSpeech {
|
|
5
|
+
constructor (data) {
|
|
6
|
+
data.album = data.contents.id;
|
|
7
|
+
data.encodedBy = 'Amazon Polly';
|
|
8
|
+
super(data);
|
|
9
|
+
}
|
|
10
10
|
};
|
package/src/classes/Rasterize.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const
|
|
2
|
-
Cheer = require('./Cheer'),
|
|
3
|
-
Rasterize = class Rasterize extends Cheer {
|
|
4
|
-
beforeSend (archive) {
|
|
5
|
-
const
|
|
6
|
-
{src} = this.config;
|
|
7
|
-
|
|
8
|
-
archive.directory(src, false);
|
|
9
|
-
super.beforeSend(archive);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
1
|
+
const
|
|
2
|
+
Cheer = require('./Cheer'),
|
|
3
|
+
Rasterize = class Rasterize extends Cheer {
|
|
4
|
+
beforeSend (archive) {
|
|
5
|
+
const
|
|
6
|
+
{src} = this.config;
|
|
7
|
+
|
|
8
|
+
archive.directory(src, false);
|
|
9
|
+
super.beforeSend(archive);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
13
|
module.exports = Rasterize;
|