@makefully/dutifully 1.18.0 → 1.20.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 +9 -0
- package/README.md +35 -2
- package/package.json +4 -2
- package/src/classes/Cheer.js +14 -6
- package/src/classes/Translate.js +47 -0
- package/src/index.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.20.0
|
|
6
|
+
|
|
7
|
+
- Add `translate` client for Amazon Translate (Cheerfully script JSON or language-matrix CSV/TSV).
|
|
8
|
+
- Support `ignore` for phrases left untranslated.
|
|
9
|
+
|
|
10
|
+
## 1.19.0
|
|
11
|
+
|
|
12
|
+
- Authenticate Showfully yap chores with `Authorization: Bearer` and `POST /yap/:service` (token no longer in the URL path).
|
|
13
|
+
|
|
5
14
|
## 1.18.0
|
|
6
15
|
|
|
7
16
|
- Store GIF content hashes in a Comment Extension (`CheerfullyHashes:{...}`), lossless.
|
package/README.md
CHANGED
|
@@ -11,10 +11,12 @@ To use the API, you will need to specify a root `./env-cheerfully.json` file wit
|
|
|
11
11
|
```javascript
|
|
12
12
|
{
|
|
13
13
|
"server": "http://server:port",
|
|
14
|
-
"accessToken": "
|
|
14
|
+
"accessToken": "BearerTokenForShowfullyYap"
|
|
15
15
|
}
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
`accessToken` is sent as `Authorization: Bearer …` on yap submit/status/download (Showfully 1.4+). For local Showfully, use the same value as `SHOWFULLY_DEBUG_TOKEN` with `SHOWFULLY_ALLOW_DEBUG_TOKEN=1`.
|
|
19
|
+
|
|
18
20
|
## Services
|
|
19
21
|
|
|
20
22
|
All services can be specified in `cheerfully.json` as described in the following sections. Services can be run as scripts specified in `package.json` as:
|
|
@@ -353,9 +355,40 @@ Script lines may also include an optional `events` array for one-shot timed mark
|
|
|
353
355
|
|
|
354
356
|
Cheerfully resolves these against caption timings and exports them in parallel using the same caption `format` (`events.json`, `{id}.events.vtt` / `.srt` / `.sami` / `.smi` / `.lrc`, or a separate MP3 SYLT frame with content type `EVENTS` labeled `"events"`).
|
|
355
357
|
|
|
358
|
+
### Translate
|
|
359
|
+
|
|
360
|
+
This text-to-text service translates Cheerfully scripts or language-matrix CSV/TSV via Amazon Translate. Set jobs in `cheerfully.json`:
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
{
|
|
364
|
+
"translate": [{
|
|
365
|
+
"script": "./example/script.json",
|
|
366
|
+
"language": "en-US",
|
|
367
|
+
"languages": ["es-ES", "fr-FR"],
|
|
368
|
+
"output": "./example/scripts/",
|
|
369
|
+
"ignore": ["Makefully Studios"]
|
|
370
|
+
}, {
|
|
371
|
+
"script": "./example/strings.csv",
|
|
372
|
+
"language": "en-US",
|
|
373
|
+
"languages": ["es-ES", "fr-FR"],
|
|
374
|
+
"output": "./example/scripts/"
|
|
375
|
+
}]
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
* `script` — path to a Cheerfully `.json` script or a language-matrix `.csv` / `.tsv` (first column = ids, first row = language tags).
|
|
380
|
+
* `language` — source locale (CSV: source column). Matrix jobs require this; JSON may use `auto`.
|
|
381
|
+
* `languages` — target locales to produce or fill.
|
|
382
|
+
* `format` / `exports` — optional. Defaults to the source extension (`json`, `csv`, or `tsv`).
|
|
383
|
+
* `ignore` — phrases left untranslated.
|
|
384
|
+
|
|
385
|
+
JSON sources write `{lang}/{basename}.{ext}` under `output`. CSV/TSV sources write an updated matrix file and leave existing non-empty cells unchanged.
|
|
386
|
+
|
|
387
|
+
Supported formats: `json`, `i18n`, `csv`, `tsv`, `po`, `xliff`, `properties`, `yml` / `yaml`, `strings`, `xml`.
|
|
388
|
+
|
|
356
389
|
## Example
|
|
357
390
|
|
|
358
|
-
Find an example script in the `./examples/` folder. You can run either `npm run test-elevenlabs` or `npm run test-polly` to create VO tracks in the examples folder that you can then use to try out `npm run test-rhubarb` and `npm run test-transcription`. Sample sprites for atlas packing are under `./example/sprites/`; run `npm run test-packfully` to pack them into `./example/atlases/`.
|
|
391
|
+
Find an example script in the `./examples/` folder. You can run either `npm run test-elevenlabs` or `npm run test-polly` to create VO tracks in the examples folder that you can then use to try out `npm run test-rhubarb` and `npm run test-transcription`. Sample sprites for atlas packing are under `./example/sprites/`; run `npm run test-packfully` to pack them into `./example/atlases/`. Run `npm run test-translate` to translate `./example/script.json` and `./example/strings.csv` into `./example/scripts/`.
|
|
359
392
|
|
|
360
393
|
These examples are specified using a JSON definition in `./cheerfully.json` which you can copy or modify to set different generation parameters as supported by Cheerfully.
|
|
361
394
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makefully/dutifully",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Client tools for Cheerfully service.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"test-sharp": "node ./cheer.js -service sharp",
|
|
29
29
|
"test-stackfully": "node ./cheer.js -service stackfully",
|
|
30
30
|
"test-transcription": "node ./cheer.js -service transcription",
|
|
31
|
+
"test-translate": "node ./cheer.js -service translate",
|
|
31
32
|
"say": "node ./say.js"
|
|
32
33
|
},
|
|
33
34
|
"repository": {
|
|
@@ -50,7 +51,8 @@
|
|
|
50
51
|
"packfully",
|
|
51
52
|
"atlas",
|
|
52
53
|
"spritesheet",
|
|
53
|
-
"classfully"
|
|
54
|
+
"classfully",
|
|
55
|
+
"translate"
|
|
54
56
|
],
|
|
55
57
|
"author": "Derek Detweiler <derek@makefullystudios.com>",
|
|
56
58
|
"contributors": [
|
package/src/classes/Cheer.js
CHANGED
|
@@ -15,13 +15,17 @@ const
|
|
|
15
15
|
}
|
|
16
16
|
return buf.subarray(0, max).toString('utf8').replace(/\s+/g, ' ').trim();
|
|
17
17
|
},
|
|
18
|
-
|
|
18
|
+
authHeaders = (accessToken) => (accessToken
|
|
19
|
+
? {Authorization: `Bearer ${accessToken}`}
|
|
20
|
+
: {}),
|
|
21
|
+
postStream = (url, stream, headers = {}) => new Promise ((resolve, reject) => {
|
|
19
22
|
const
|
|
20
23
|
protocol = url.startsWith('https') ? https : http;
|
|
21
24
|
req = protocol.request(url, {
|
|
22
25
|
method: 'post',
|
|
23
26
|
headers: {
|
|
24
|
-
'Content-Type': 'application/zip'
|
|
27
|
+
'Content-Type': 'application/zip',
|
|
28
|
+
...headers
|
|
25
29
|
}
|
|
26
30
|
}, async (res) => {
|
|
27
31
|
let data = '';
|
|
@@ -61,7 +65,7 @@ const
|
|
|
61
65
|
let response = null;
|
|
62
66
|
|
|
63
67
|
try {
|
|
64
|
-
response = await fetchStream(`${url}/${choreId}
|
|
68
|
+
response = await fetchStream(`${url}/${choreId}`, headers);
|
|
65
69
|
} catch (e) {
|
|
66
70
|
console.warn(e);
|
|
67
71
|
|
|
@@ -101,11 +105,11 @@ const
|
|
|
101
105
|
|
|
102
106
|
stream.pipe(req);
|
|
103
107
|
}),
|
|
104
|
-
fetchStream = (url) => new Promise((resolve, reject) => {
|
|
108
|
+
fetchStream = (url, headers = {}) => new Promise((resolve, reject) => {
|
|
105
109
|
const
|
|
106
110
|
protocol = url.startsWith('https') ? https : http;
|
|
107
111
|
|
|
108
|
-
protocol.get(url, (res) => {
|
|
112
|
+
protocol.get(url, {headers}, (res) => {
|
|
109
113
|
const
|
|
110
114
|
contentType = res.headers['content-type'] || '',
|
|
111
115
|
statusCode = res.statusCode || 0;
|
|
@@ -285,7 +289,11 @@ const
|
|
|
285
289
|
try {
|
|
286
290
|
const
|
|
287
291
|
archiveStream = await archive((archive) => this.beforeSend(archive)),
|
|
288
|
-
data = await postStream(
|
|
292
|
+
data = await postStream(
|
|
293
|
+
`${cleanPath(server)}/yap/${service}`,
|
|
294
|
+
archiveStream,
|
|
295
|
+
authHeaders(accessToken)
|
|
296
|
+
);
|
|
289
297
|
|
|
290
298
|
// listen for all archive data to be written
|
|
291
299
|
archiveStream.on('close', function () {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const
|
|
2
|
+
path = require('path'),
|
|
3
|
+
Cheer = require('./Cheer'),
|
|
4
|
+
MATRIX_EXTS = new Set(['csv', 'tsv']),
|
|
5
|
+
Translate = class Translate extends Cheer {
|
|
6
|
+
async prepare (data) {
|
|
7
|
+
const
|
|
8
|
+
{config} = this,
|
|
9
|
+
scriptPath = config.script;
|
|
10
|
+
|
|
11
|
+
this.matrixMode = false;
|
|
12
|
+
this.scriptPath = null;
|
|
13
|
+
|
|
14
|
+
if (scriptPath) {
|
|
15
|
+
const
|
|
16
|
+
ext = path.extname(scriptPath).slice(1).toLowerCase(),
|
|
17
|
+
basename = path.basename(scriptPath, path.extname(scriptPath));
|
|
18
|
+
|
|
19
|
+
this.scriptPath = scriptPath;
|
|
20
|
+
config.basename = config.basename ?? basename;
|
|
21
|
+
|
|
22
|
+
if (!config.format && !config.exports) {
|
|
23
|
+
config.format = MATRIX_EXTS.has(ext) ? ext : 'json';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (MATRIX_EXTS.has(ext)) {
|
|
27
|
+
this.matrixMode = true;
|
|
28
|
+
config.matrixFile = path.basename(scriptPath);
|
|
29
|
+
delete config.script;
|
|
30
|
+
} else {
|
|
31
|
+
await this.replaceConfigPathWithJSON('script', 'files');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return super.prepare(data);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
beforeSend (archive) {
|
|
39
|
+
if (this.matrixMode && this.scriptPath) {
|
|
40
|
+
archive.file(this.scriptPath, {name: this.config.matrixFile});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return super.beforeSend(archive);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
module.exports = Translate;
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,8 @@ const
|
|
|
13
13
|
rhubarb: LipSync,
|
|
14
14
|
sharp: require('./classes/Sharp'),
|
|
15
15
|
stackfully: require('./classes/Stackfully'),
|
|
16
|
-
transcription: require('./classes/Transcription')
|
|
16
|
+
transcription: require('./classes/Transcription'),
|
|
17
|
+
translate: require('./classes/Translate')
|
|
17
18
|
},
|
|
18
19
|
getJSON = require('./helpers/getJSON'),
|
|
19
20
|
send = async function (contents) {
|