@makefully/dutifully 1.22.1 → 1.23.1
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 +11 -0
- package/README.md +47 -7
- package/package.json +5 -2
- package/src/classes/Cheer.js +2 -1
- package/src/classes/ElevenLabs.js +3 -6
- package/src/helpers/applyServiceAuth.js +89 -0
- package/src/helpers/jobExports.js +16 -0
- package/src/helpers/resolveProviderService.js +86 -0
- package/src/index.js +41 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.23.1
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Shared `auth` on jobs and `env-cheerfully.json` `auth.<service>` map (job wins; env fills defaults). Legacy `elevenLabsApiKey` and top-level ElevenLabs `apiKey` still map into `auth.apiKey`.
|
|
10
|
+
|
|
11
|
+
## 1.23.0
|
|
12
|
+
|
|
13
|
+
- Provider umbrellas: `translate` (`amazon` default → `amazontranslate`, or `deepl` / `google` / `microsoft`), `lipsync` (`rhubarb` default / `allosaurus`), and `voiceover` (`elevenlabs` default / `polly`) resolve to Cheerfully concrete services before Yap submit.
|
|
14
|
+
- Concrete MT parsers: `amazontranslate`, `deepl`, `googletranslate`, `microsofttranslate`.
|
|
15
|
+
|
|
5
16
|
## 1.22.1
|
|
6
17
|
|
|
7
18
|
- Allow translate `format: "catalog"` (Cheerfully flat `{lang}.json` app catalogs) alongside existing loc formats.
|
package/README.md
CHANGED
|
@@ -6,17 +6,28 @@ Client API for Cheerfully services. Cheerfully makes voice-over easy.
|
|
|
6
6
|
npm install @makefully/dutifully
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
To use the API, you will need
|
|
9
|
+
To use the API, you will need a root `./env-cheerfully.json` with Showfully Yap credentials and optional per-service auth defaults:
|
|
10
10
|
|
|
11
11
|
```javascript
|
|
12
12
|
{
|
|
13
13
|
"server": "http://server:port",
|
|
14
|
-
"accessToken": "BearerTokenForShowfullyYap"
|
|
14
|
+
"accessToken": "BearerTokenForShowfullyYap",
|
|
15
|
+
"auth": {
|
|
16
|
+
"elevenlabs": { "apiKey": "…" },
|
|
17
|
+
"deepl": { "apiKey": "…", "serverUrl": "https://api-free.deepl.com" },
|
|
18
|
+
"googletranslate": { "apiKey": "…" },
|
|
19
|
+
"microsofttranslate": { "key": "…", "region": "eastus" },
|
|
20
|
+
"amazontranslate": { "config": { } },
|
|
21
|
+
"polly": { "config": { }, "bucket": "…", "root": "…" },
|
|
22
|
+
"transcription": { "config": { }, "bucket": "…", "root": "…" }
|
|
23
|
+
}
|
|
15
24
|
}
|
|
16
25
|
```
|
|
17
26
|
|
|
18
27
|
`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
28
|
|
|
29
|
+
Job listings may include their own `auth` object (same shapes). Dutifully merges `auth.<service>` from env into each job; **job `auth` wins**. Legacy `elevenLabsApiKey` still maps to `auth.elevenlabs.apiKey`.
|
|
30
|
+
|
|
20
31
|
## Services
|
|
21
32
|
|
|
22
33
|
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:
|
|
@@ -100,7 +111,7 @@ await cheerfully.say('The build is complete');
|
|
|
100
111
|
```
|
|
101
112
|
|
|
102
113
|
|
|
103
|
-
Voice settings come from the first `elevenlabs` entry in `cheerfully.json` (same as other ElevenLabs chores). Server credentials and `elevenLabsApiKey` come from `env-cheerfully.json`. Cached files are keyed by voice + text, so repeats play immediately without regenerating.
|
|
114
|
+
Voice settings come from the first `elevenlabs` entry in `cheerfully.json` (same as other ElevenLabs chores). Server credentials and optional `auth.elevenlabs` (or legacy `elevenLabsApiKey`) come from `env-cheerfully.json`. Cached files are keyed by voice + text, so repeats play immediately without regenerating.
|
|
104
115
|
|
|
105
116
|
### ElevenLabs
|
|
106
117
|
|
|
@@ -124,14 +135,20 @@ Specifying the `model` is optional: if unspecified, Cheerfully tries to look up
|
|
|
124
135
|
|
|
125
136
|
Specifying `updateAllMetaData` is `false` by default. If it's set to `true`, album, title, and unsynchronized lyrics are appended to any MP3's in the source directory that were not generated.
|
|
126
137
|
|
|
127
|
-
You may include
|
|
138
|
+
You may include credentials on the job as `auth.apiKey`, or set defaults in `env-cheerfully.json`:
|
|
128
139
|
|
|
129
140
|
```javascript
|
|
130
141
|
{
|
|
131
|
-
"
|
|
142
|
+
"auth": {
|
|
143
|
+
"elevenlabs": {
|
|
144
|
+
"apiKey": "elevenlabsapikeyforyouraccount"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
132
147
|
}
|
|
133
148
|
```
|
|
134
149
|
|
|
150
|
+
Legacy `elevenLabsApiKey` at the top level of `env-cheerfully.json` is still accepted.
|
|
151
|
+
|
|
135
152
|
### FFMPEG
|
|
136
153
|
|
|
137
154
|
This audio file process accepts ffmpeg commandline arguments to perform operations on an audio file.
|
|
@@ -432,13 +449,22 @@ Script lines may also include an optional `events` array for one-shot timed mark
|
|
|
432
449
|
|
|
433
450
|
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"`).
|
|
434
451
|
|
|
435
|
-
###
|
|
452
|
+
### Provider umbrellas (`translate`, `lipsync`, `voiceover`)
|
|
453
|
+
|
|
454
|
+
Dutifully logical services pick a Cheerfully processor via per-job `provider` (stripped before upload):
|
|
455
|
+
|
|
456
|
+
| Dutifully `-service` | `provider` | Default | Cheerfully target |
|
|
457
|
+
| --- | --- | --- | --- |
|
|
458
|
+
| `translate` | `amazon`, `deepl`, `google`, `microsoft` | `amazon` | `amazontranslate`, `deepl`, `googletranslate`, `microsofttranslate` |
|
|
459
|
+
| `lipsync` | `rhubarb`, `allosaurus` | `rhubarb` | same as provider |
|
|
460
|
+
| `voiceover` | `polly`, `elevenlabs` | `elevenlabs` | same as provider |
|
|
436
461
|
|
|
437
|
-
|
|
462
|
+
Concrete keys (`deepl`, `polly`, `rhubarb`, …) still work without `provider`.
|
|
438
463
|
|
|
439
464
|
```javascript
|
|
440
465
|
{
|
|
441
466
|
"translate": [{
|
|
467
|
+
"provider": "amazon",
|
|
442
468
|
"script": "./example/script.json",
|
|
443
469
|
"language": "en-US",
|
|
444
470
|
"languages": ["es-ES", "fr-FR"],
|
|
@@ -449,15 +475,29 @@ This text-to-text service translates Cheerfully scripts or language-matrix CSV/T
|
|
|
449
475
|
"language": "en-US",
|
|
450
476
|
"languages": ["es-ES", "fr-FR"],
|
|
451
477
|
"output": "./example/scripts/"
|
|
478
|
+
}],
|
|
479
|
+
"voiceover": [{
|
|
480
|
+
"provider": "elevenlabs",
|
|
481
|
+
"script": "./example/script.json",
|
|
482
|
+
"output": "./example/vo/en/",
|
|
483
|
+
"voice": "21m00Tcm4TlvDq8ikWAM"
|
|
484
|
+
}],
|
|
485
|
+
"lipsync": [{
|
|
486
|
+
"provider": "rhubarb",
|
|
487
|
+
"src": "./example/vo/en/",
|
|
488
|
+
"output": "./example/lipsync/en/"
|
|
452
489
|
}]
|
|
453
490
|
}
|
|
454
491
|
```
|
|
455
492
|
|
|
493
|
+
Translate job fields:
|
|
494
|
+
|
|
456
495
|
* `script` — path to a Cheerfully `.json` script or a language-matrix `.csv` / `.tsv` (first column = ids, first row = language tags).
|
|
457
496
|
* `language` — source locale (CSV: source column). Matrix jobs require this; JSON may use `auto`.
|
|
458
497
|
* `languages` — target locales to produce or fill.
|
|
459
498
|
* `format` / `exports` — optional. Defaults to the source extension (`json`, `csv`, or `tsv`).
|
|
460
499
|
* `ignore` — phrases left untranslated.
|
|
500
|
+
* `provider` — MT engine (see table); default `amazon`.
|
|
461
501
|
|
|
462
502
|
JSON sources write `{lang}/{basename}.{ext}` under `output` (`catalog` → `{lang}.json`). CSV/TSV sources write an updated matrix file and leave existing non-empty cells unchanged.
|
|
463
503
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makefully/dutifully",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.1",
|
|
4
4
|
"description": "Client tools for Cheerfully service.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -52,7 +52,10 @@
|
|
|
52
52
|
"atlas",
|
|
53
53
|
"spritesheet",
|
|
54
54
|
"classfully",
|
|
55
|
-
"translate"
|
|
55
|
+
"translate",
|
|
56
|
+
"deepl",
|
|
57
|
+
"voiceover",
|
|
58
|
+
"lipsync"
|
|
56
59
|
],
|
|
57
60
|
"author": "Derek Detweiler <derek@makefullystudios.com>",
|
|
58
61
|
"contributors": [
|
package/src/classes/Cheer.js
CHANGED
|
@@ -6,6 +6,7 @@ const
|
|
|
6
6
|
https = require('https'),
|
|
7
7
|
{PassThrough} = require('stream'),
|
|
8
8
|
unzipper = require('unzip-stream'),
|
|
9
|
+
{applyServiceAuth} = require('../helpers/applyServiceAuth'),
|
|
9
10
|
cleanPath = (path) => path[path.length - 1] === '/' ? path.substring(0, path.length - 1) : path,
|
|
10
11
|
isZipMagic = (buf) => buf && buf.length >= 4 && buf[0] === 0x50 && buf[1] === 0x4b &&
|
|
11
12
|
((buf[2] === 0x03 && buf[3] === 0x04) || (buf[2] === 0x05 && buf[3] === 0x06) || (buf[2] === 0x07 && buf[3] === 0x08)),
|
|
@@ -264,9 +265,9 @@ const
|
|
|
264
265
|
},
|
|
265
266
|
Cheer = class {
|
|
266
267
|
constructor ({config, contents}) {
|
|
267
|
-
this.config = config;
|
|
268
268
|
this.contents = contents;
|
|
269
269
|
this.service = contents.service;
|
|
270
|
+
this.config = applyServiceAuth(config, contents, contents.service);
|
|
270
271
|
}
|
|
271
272
|
|
|
272
273
|
prepare ({difference = true, extract = true}) {
|
|
@@ -4,14 +4,11 @@ const
|
|
|
4
4
|
module.exports = class ElevenLabs extends TextToSpeech {
|
|
5
5
|
constructor (data) {
|
|
6
6
|
const
|
|
7
|
-
{id
|
|
7
|
+
{id} = data.contents;
|
|
8
8
|
|
|
9
9
|
data.album = id;
|
|
10
10
|
data.encodedBy = 'ElevenLabs';
|
|
11
|
-
|
|
12
|
-
data.config.apiKey = elevenLabsApiKey;
|
|
13
|
-
}
|
|
14
|
-
|
|
11
|
+
// Auth (env auth.elevenlabs / elevenLabsApiKey / job.auth) is applied in Cheer.
|
|
15
12
|
super(data);
|
|
16
13
|
}
|
|
17
|
-
};
|
|
14
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge Dutifully env-cheerfully.json `auth.<service>` into a job's `auth`.
|
|
3
|
+
* Job-level auth wins; env fills defaults. Legacy `elevenLabsApiKey` maps to elevenlabs.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const isPlainObject = (value) => (
|
|
7
|
+
value != null && typeof value === 'object' && !Array.isArray(value)
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Normalize legacy env aliases into `contents.auth`.
|
|
12
|
+
* @param {Record<string, unknown>} contents
|
|
13
|
+
* @returns {Record<string, unknown>}
|
|
14
|
+
*/
|
|
15
|
+
const normalizeContentsAuth = (contents = {}) => {
|
|
16
|
+
const
|
|
17
|
+
auth = isPlainObject(contents.auth) ? {...contents.auth} : {};
|
|
18
|
+
|
|
19
|
+
if (contents.elevenLabsApiKey) {
|
|
20
|
+
auth.elevenlabs = {
|
|
21
|
+
...(isPlainObject(auth.elevenlabs) ? auth.elevenlabs : {}),
|
|
22
|
+
apiKey: contents.elevenLabsApiKey
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return auth;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Apply service auth defaults onto a job config (mutates config).
|
|
31
|
+
* @param {Record<string, unknown>} config job listing from cheerfully.json
|
|
32
|
+
* @param {Record<string, unknown>} contents merged cheer + env + CLI
|
|
33
|
+
* @param {string} [service] Cheerfully service id (defaults to contents.service)
|
|
34
|
+
* @returns {Record<string, unknown>} config
|
|
35
|
+
*/
|
|
36
|
+
const applyServiceAuth = (config, contents = {}, service = contents.service) => {
|
|
37
|
+
if (!config || typeof config !== 'object') {
|
|
38
|
+
return config;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const
|
|
42
|
+
authMap = normalizeContentsAuth(contents),
|
|
43
|
+
fromEnv = service && isPlainObject(authMap[service]) ? {...authMap[service]} : {},
|
|
44
|
+
fromJob = isPlainObject(config.auth) ? {...config.auth} : {},
|
|
45
|
+
// Legacy ElevenLabs top-level apiKey on the job
|
|
46
|
+
legacyJobKey = service === 'elevenlabs'
|
|
47
|
+
&& typeof config.apiKey === 'string'
|
|
48
|
+
&& config.apiKey
|
|
49
|
+
&& fromJob.apiKey == null
|
|
50
|
+
? {apiKey: config.apiKey}
|
|
51
|
+
: {};
|
|
52
|
+
|
|
53
|
+
const
|
|
54
|
+
merged = {
|
|
55
|
+
...fromEnv,
|
|
56
|
+
...legacyJobKey,
|
|
57
|
+
...fromJob
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (isPlainObject(fromEnv.config) || isPlainObject(fromJob.config) || isPlainObject(legacyJobKey.config)) {
|
|
61
|
+
merged.config = {
|
|
62
|
+
...(isPlainObject(fromEnv.config) ? fromEnv.config : {}),
|
|
63
|
+
...(isPlainObject(fromJob.config) ? fromJob.config : {})
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (isPlainObject(fromEnv.config?.credentials) || isPlainObject(fromJob.config?.credentials)) {
|
|
67
|
+
merged.config.credentials = {
|
|
68
|
+
...(isPlainObject(fromEnv.config?.credentials) ? fromEnv.config.credentials : {}),
|
|
69
|
+
...(isPlainObject(fromJob.config?.credentials) ? fromJob.config.credentials : {})
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (Object.keys(merged).length) {
|
|
75
|
+
config.auth = merged;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Prefer auth container; drop legacy top-level apiKey once folded in.
|
|
79
|
+
if (service === 'elevenlabs' && config.apiKey != null && config.auth?.apiKey) {
|
|
80
|
+
delete config.apiKey;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return config;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
normalizeContentsAuth,
|
|
88
|
+
applyServiceAuth
|
|
89
|
+
};
|
|
@@ -28,6 +28,22 @@ const EXPORT_CATALOG = {
|
|
|
28
28
|
keys: ['format', 'exports'],
|
|
29
29
|
formats: TRANSLATE_FORMATS
|
|
30
30
|
},
|
|
31
|
+
amazontranslate: {
|
|
32
|
+
keys: ['format', 'exports'],
|
|
33
|
+
formats: TRANSLATE_FORMATS
|
|
34
|
+
},
|
|
35
|
+
deepl: {
|
|
36
|
+
keys: ['format', 'exports'],
|
|
37
|
+
formats: TRANSLATE_FORMATS
|
|
38
|
+
},
|
|
39
|
+
googletranslate: {
|
|
40
|
+
keys: ['format', 'exports'],
|
|
41
|
+
formats: TRANSLATE_FORMATS
|
|
42
|
+
},
|
|
43
|
+
microsofttranslate: {
|
|
44
|
+
keys: ['format', 'exports'],
|
|
45
|
+
formats: TRANSLATE_FORMATS
|
|
46
|
+
},
|
|
31
47
|
packfully: {
|
|
32
48
|
keys: ['format', 'exports', 'exportFormat'],
|
|
33
49
|
formats: PACKFULLY_FORMATS
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map Dutifully umbrella services + provider → Cheerfully concrete service ids.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const
|
|
6
|
+
UMBRELLAS = {
|
|
7
|
+
translate: {
|
|
8
|
+
defaultProvider: 'amazon',
|
|
9
|
+
providers: {
|
|
10
|
+
amazon: 'amazontranslate',
|
|
11
|
+
amazontranslate: 'amazontranslate',
|
|
12
|
+
deepl: 'deepl',
|
|
13
|
+
google: 'googletranslate',
|
|
14
|
+
googletranslate: 'googletranslate',
|
|
15
|
+
microsoft: 'microsofttranslate',
|
|
16
|
+
microsofttranslate: 'microsofttranslate'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
lipsync: {
|
|
20
|
+
defaultProvider: 'rhubarb',
|
|
21
|
+
providers: {
|
|
22
|
+
rhubarb: 'rhubarb',
|
|
23
|
+
allosaurus: 'allosaurus'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
voiceover: {
|
|
27
|
+
defaultProvider: 'elevenlabs',
|
|
28
|
+
providers: {
|
|
29
|
+
polly: 'polly',
|
|
30
|
+
elevenlabs: 'elevenlabs'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
isUmbrella = (service) => Boolean(UMBRELLAS[service]),
|
|
35
|
+
/**
|
|
36
|
+
* @returns {{ cheerfullyService: string, provider: string, job: object }}
|
|
37
|
+
*/
|
|
38
|
+
resolveProviderService = (umbrella, job = {}) => {
|
|
39
|
+
const
|
|
40
|
+
table = UMBRELLAS[umbrella];
|
|
41
|
+
|
|
42
|
+
if (!table) {
|
|
43
|
+
const
|
|
44
|
+
cleaned = {...job};
|
|
45
|
+
|
|
46
|
+
delete cleaned.provider;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
cheerfullyService: umbrella,
|
|
50
|
+
provider: null,
|
|
51
|
+
job: cleaned
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const
|
|
56
|
+
raw = job.provider == null || job.provider === ''
|
|
57
|
+
? table.defaultProvider
|
|
58
|
+
: String(job.provider).toLowerCase().trim(),
|
|
59
|
+
cheerfullyService = table.providers[raw];
|
|
60
|
+
|
|
61
|
+
if (!cheerfullyService) {
|
|
62
|
+
const
|
|
63
|
+
allowed = [...new Set(Object.keys(table.providers))].sort().join(', ');
|
|
64
|
+
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Unknown provider "${job.provider}" for "${umbrella}". Use one of: ${allowed}.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const
|
|
71
|
+
cleaned = {...job};
|
|
72
|
+
|
|
73
|
+
delete cleaned.provider;
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
cheerfullyService,
|
|
77
|
+
provider: raw,
|
|
78
|
+
job: cleaned
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
UMBRELLAS,
|
|
84
|
+
isUmbrella,
|
|
85
|
+
resolveProviderService
|
|
86
|
+
};
|
package/src/index.js
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
/* global console, process, require */
|
|
3
3
|
const
|
|
4
4
|
LipSync = require('./classes/LipSync'),
|
|
5
|
+
Translate = require('./classes/Translate'),
|
|
5
6
|
parsers = {
|
|
6
7
|
allosaurus: LipSync,
|
|
8
|
+
amazontranslate: Translate,
|
|
7
9
|
classfully: require('./classes/Classfully'),
|
|
10
|
+
deepl: Translate,
|
|
8
11
|
elevenlabs: require('./classes/ElevenLabs'),
|
|
9
12
|
ffmpeg: require('./classes/FFMPEG'),
|
|
13
|
+
googletranslate: Translate,
|
|
14
|
+
microsofttranslate: Translate,
|
|
10
15
|
packfully: require('./classes/Packfully'),
|
|
11
16
|
polly: require('./classes/Polly'),
|
|
12
17
|
rasterize: require('./classes/Rasterize'),
|
|
@@ -14,10 +19,12 @@ const
|
|
|
14
19
|
sharp: require('./classes/Sharp'),
|
|
15
20
|
stackfully: require('./classes/Stackfully'),
|
|
16
21
|
transcription: require('./classes/Transcription'),
|
|
17
|
-
translate
|
|
22
|
+
// Concrete only — umbrellas (translate / lipsync / voiceover) resolve first.
|
|
23
|
+
translate: Translate
|
|
18
24
|
},
|
|
19
25
|
getJSON = require('./helpers/getJSON'),
|
|
20
26
|
{normalizeOnly, filterJobsById} = require('./helpers/filterJobs'),
|
|
27
|
+
{isUmbrella, resolveProviderService} = require('./helpers/resolveProviderService'),
|
|
21
28
|
send = async function (contents) {
|
|
22
29
|
const
|
|
23
30
|
{id, service} = contents,
|
|
@@ -36,11 +43,40 @@ const
|
|
|
36
43
|
continue;
|
|
37
44
|
}
|
|
38
45
|
|
|
46
|
+
let
|
|
47
|
+
cheerfullyService = service,
|
|
48
|
+
jobConfig = config;
|
|
49
|
+
|
|
50
|
+
if (isUmbrella(service)) {
|
|
51
|
+
try {
|
|
52
|
+
const
|
|
53
|
+
resolved = resolveProviderService(service, config);
|
|
54
|
+
|
|
55
|
+
cheerfullyService = resolved.cheerfullyService;
|
|
56
|
+
jobConfig = resolved.job;
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.warn(e.message);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const
|
|
64
|
+
Parser = parsers[cheerfullyService];
|
|
65
|
+
|
|
66
|
+
if (!Parser) {
|
|
67
|
+
console.warn(`No Dutifully parser for Cheerfully service "${cheerfullyService}".`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
const
|
|
40
|
-
|
|
72
|
+
contentsForJob = {
|
|
73
|
+
...contents,
|
|
74
|
+
service: cheerfullyService
|
|
75
|
+
},
|
|
76
|
+
serviceHandler = new Parser({config: jobConfig, contents: contentsForJob});
|
|
41
77
|
|
|
42
78
|
try {
|
|
43
|
-
await serviceHandler.prepare({...
|
|
79
|
+
await serviceHandler.prepare({...contentsForJob, ...jobConfig});
|
|
44
80
|
} catch (e) {
|
|
45
81
|
console.warn(e.message);
|
|
46
82
|
continue;
|
|
@@ -48,10 +84,10 @@ const
|
|
|
48
84
|
|
|
49
85
|
try {
|
|
50
86
|
await serviceHandler.send({
|
|
51
|
-
instanceId: `${id}-${
|
|
87
|
+
instanceId: `${id}-${cheerfullyService}${length > 1 ? `-${index}` : ''}`
|
|
52
88
|
});
|
|
53
89
|
} catch (e) {
|
|
54
|
-
console.warn(`Error running "${
|
|
90
|
+
console.warn(`Error running "${cheerfullyService}" (${index}): ${e.message || e}`);
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
};
|