@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 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": "accessTokenToUseCheerfullyService"
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.18.0",
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": [
@@ -15,13 +15,17 @@ const
15
15
  }
16
16
  return buf.subarray(0, max).toString('utf8').replace(/\s+/g, ' ').trim();
17
17
  },
18
- postStream = (url, stream) => new Promise ((resolve, reject) => {
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(`${cleanPath(server)}/yap/${service}/${accessToken}`, archiveStream);
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) {