@pixwel/pixwel-sdk 1.1.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/.babelrc +3 -0
- package/.editorconfig +36 -0
- package/.vs/slnx.sqlite +0 -0
- package/.vscode/launch.json +0 -0
- package/coverage/clover.xml +7 -0
- package/coverage/coverage-final.json +1 -0
- package/coverage/lcov-report/Ass.js.html +651 -0
- package/coverage/lcov-report/Asset.js.html +129 -0
- package/coverage/lcov-report/Filename.js.html +849 -0
- package/coverage/lcov-report/Ingest.js.html +591 -0
- package/coverage/lcov-report/IngestFile.js.html +87 -0
- package/coverage/lcov-report/IngestFileDrop.js.html +540 -0
- package/coverage/lcov-report/Order.js.html +162 -0
- package/coverage/lcov-report/Srt.js.html +333 -0
- package/coverage/lcov-report/Sub.js.html +177 -0
- package/coverage/lcov-report/TimeFormat.js.html +210 -0
- package/coverage/lcov-report/base.css +223 -0
- package/coverage/lcov-report/block-navigation.js +63 -0
- package/coverage/lcov-report/index.html +84 -0
- package/coverage/lcov-report/lib/Filename.js.html +720 -0
- package/coverage/lcov-report/lib/index.html +97 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +1 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +158 -0
- package/coverage/lcov-report/test/index.html +97 -0
- package/coverage/lcov-report/test/mocks.js.html +423 -0
- package/coverage/lcov.info +0 -0
- package/dist/index.js +61 -0
- package/dist/src/Ass.js +200 -0
- package/dist/src/Asset.js +41 -0
- package/dist/src/Filename.js +252 -0
- package/dist/src/Ingest.js +200 -0
- package/dist/src/IngestFile.js +17 -0
- package/dist/src/IngestFileDrop.js +178 -0
- package/dist/src/Order.js +58 -0
- package/dist/src/Srt.js +102 -0
- package/dist/src/Sub.js +42 -0
- package/dist/src/TimeFormat.js +48 -0
- package/index.js +6 -0
- package/package.json +26 -0
- package/src/Ass.js +195 -0
- package/src/Asset.js +20 -0
- package/src/Filename.js +260 -0
- package/src/Ingest.js +175 -0
- package/src/IngestFile.js +6 -0
- package/src/IngestFileDrop.js +157 -0
- package/src/Order.js +31 -0
- package/src/Srt.js +89 -0
- package/src/Sub.js +37 -0
- package/src/TimeFormat.js +48 -0
- package/src/docs.json +1 -0
- package/test/Ass.spec.js +150 -0
- package/test/Asset.spec.js +24 -0
- package/test/Filename.spec.js +728 -0
- package/test/Ingest.spec.js +95 -0
- package/test/Srt.spec.js +111 -0
- package/test/Sub.spec.js +75 -0
- package/test/TimeFormat.spec.js +84 -0
- package/test/mocks/mediainfo.mock.js +67 -0
- package/test/mocks/mediainfo.png.mock.js +22 -0
- package/test/mocks/mocks.js +118 -0
- package/test/mocks/prores.mock.js +71 -0
- package/test/parse.spec.ts +927 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
8
|
+
|
|
9
|
+
var IngestFile = function IngestFile(file, order) {
|
|
10
|
+
_classCallCheck(this, IngestFile);
|
|
11
|
+
|
|
12
|
+
this.file = file;
|
|
13
|
+
}
|
|
14
|
+
// renderedName, ingest, options
|
|
15
|
+
;
|
|
16
|
+
|
|
17
|
+
exports.default = IngestFile;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
+
|
|
9
|
+
var _pixwelSdk = require("@pixwel/pixwel-sdk");
|
|
10
|
+
|
|
11
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Collects file handles from HTML5, full paths from Aspera, inspects
|
|
15
|
+
* the dropped file using mediainfo, then renames the file according to
|
|
16
|
+
* the data from Mediainfo and the Order and submits it for upload.
|
|
17
|
+
* @type {Object}
|
|
18
|
+
*/
|
|
19
|
+
var IngestFileDrop = function () {
|
|
20
|
+
/**
|
|
21
|
+
* Map that contains data from HTML5 file drop and Aspera file drop
|
|
22
|
+
* @type {Object}
|
|
23
|
+
*/
|
|
24
|
+
function IngestFileDrop(scope, Mediainfo, IngestUpload) {
|
|
25
|
+
_classCallCheck(this, IngestFileDrop);
|
|
26
|
+
|
|
27
|
+
this.map = {};
|
|
28
|
+
this.scope = scope;
|
|
29
|
+
this.IngestUpload = IngestUpload;
|
|
30
|
+
this.Mediainfo = Mediainfo;
|
|
31
|
+
this.asperaDropHandler = this.asperaDropHandler.bind(this);
|
|
32
|
+
this.htmlDropHandler = this.htmlDropHandler.bind(this);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* HTML file drop handler
|
|
36
|
+
* @param {[type]} e [description]
|
|
37
|
+
* @return {[type]} [description]
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_createClass(IngestFileDrop, [{
|
|
42
|
+
key: "htmlDropHandler",
|
|
43
|
+
value: function htmlDropHandler(e) {
|
|
44
|
+
var files = e.dataTransfer.files;
|
|
45
|
+
for (var i = 0; i < files.length; i++) {
|
|
46
|
+
this.registerHtmlFile(files[i]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Aspera drop handler
|
|
51
|
+
* @param {[type]} data [description]
|
|
52
|
+
* @return {[type]} [description]
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
}, {
|
|
56
|
+
key: "asperaDropHandler",
|
|
57
|
+
value: function asperaDropHandler(data) {
|
|
58
|
+
var that = this;
|
|
59
|
+
var files = data.files.dataTransfer.files;
|
|
60
|
+
if (!files.length) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (var i = 0; i < files.length; i++) {
|
|
64
|
+
this.registerAsperaFile(files[i]);
|
|
65
|
+
}
|
|
66
|
+
return Promise.all(this.export()).then(function (renamed) {
|
|
67
|
+
that.IngestUpload.uploadFiles(renamed, {}).then(function () {
|
|
68
|
+
that.map = {};
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Registers and HTML file drop
|
|
74
|
+
* @param {[type]} file [description]
|
|
75
|
+
* @return {[type]} [description]
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
}, {
|
|
79
|
+
key: "registerHtmlFile",
|
|
80
|
+
value: function registerHtmlFile(file) {
|
|
81
|
+
this.map[file.name] = file;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Registers and Aspera file drop
|
|
85
|
+
* @param {[type]} file [description]
|
|
86
|
+
* @return {[type]} [description]
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
}, {
|
|
90
|
+
key: "registerAsperaFile",
|
|
91
|
+
value: function registerAsperaFile(file) {
|
|
92
|
+
var basename = this.getBasename(file);
|
|
93
|
+
this.map[basename]["path"] = file.name;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Gets correct basename for MacOS and Windows
|
|
97
|
+
* @param {[type]} file [description]
|
|
98
|
+
* @return {[type]} [description]
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
}, {
|
|
102
|
+
key: "getBasename",
|
|
103
|
+
value: function getBasename(file) {
|
|
104
|
+
return file.name[0] === "/" ? file.name.split("/").pop() : file.name.split("\\").pop();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Renames and generates ingest record for internal filemap
|
|
108
|
+
* @return {[type]} [description]
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
}, {
|
|
112
|
+
key: "export",
|
|
113
|
+
value: function _export() {
|
|
114
|
+
var that = this;
|
|
115
|
+
return Object.values(this.map).map(function (file) {
|
|
116
|
+
return that.rename(file);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Renames the file and decorates it with ingest data using data from
|
|
121
|
+
* mediainfo and the Order
|
|
122
|
+
* @param {[type]} file [description]
|
|
123
|
+
* @return {[type]} [description]
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
}, {
|
|
127
|
+
key: "rename",
|
|
128
|
+
value: function rename(file) {
|
|
129
|
+
var that = this;
|
|
130
|
+
return this.Mediainfo.inform(file).then(function (meta) {
|
|
131
|
+
var order = void 0;
|
|
132
|
+
var asset = void 0;
|
|
133
|
+
var mediaType = file.type.split("/")[0];
|
|
134
|
+
|
|
135
|
+
var tags = _pixwelSdk.Ingest.mapMetaToTags(meta, mediaType);
|
|
136
|
+
|
|
137
|
+
if (!that.scope.workRequest) {
|
|
138
|
+
order = new _pixwelSdk.Order();
|
|
139
|
+
asset = new _pixwelSdk.Asset();
|
|
140
|
+
tags.Text = "txtd";
|
|
141
|
+
file.ingest = _pixwelSdk.Ingest.mapFromKnownData(that.scope.context, order, tags, that.scope.watermarks);
|
|
142
|
+
return file;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
order = new _pixwelSdk.Order(that.scope.workRequest);
|
|
146
|
+
asset = _pixwelSdk.Asset.mapFromOrder(order);
|
|
147
|
+
|
|
148
|
+
var options = {
|
|
149
|
+
tags: tags,
|
|
150
|
+
country: order.country,
|
|
151
|
+
language: order.language
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
if (that.scope.request && that.scope.request.tag) {
|
|
155
|
+
options.tags.Extra = [that.scope.request.tag.replace(" ", "-")];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
options.tags.SubDub = {
|
|
159
|
+
sub: order.isSub(),
|
|
160
|
+
dub: order.isDub()
|
|
161
|
+
};
|
|
162
|
+
if (!order.isSub() && !order.isDub()) {
|
|
163
|
+
options.tags.Text = "txtd";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var basename = _pixwelSdk.Filename.render(that.scope.tags, that.scope.assetTypes, asset, options, mediaType);
|
|
167
|
+
var extension = file.name.split(".").pop();
|
|
168
|
+
file.renderedName = basename + "." + extension;
|
|
169
|
+
file.ingest = _pixwelSdk.Ingest.mapFromKnownData(that.scope.context, order, tags, that.scope.watermarks);
|
|
170
|
+
return file;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}]);
|
|
174
|
+
|
|
175
|
+
return IngestFileDrop;
|
|
176
|
+
}();
|
|
177
|
+
|
|
178
|
+
exports.default = IngestFileDrop;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
+
|
|
9
|
+
var _lodash = require("lodash");
|
|
10
|
+
|
|
11
|
+
var _lodash2 = _interopRequireDefault(_lodash);
|
|
12
|
+
|
|
13
|
+
var _Filename = require("./Filename.js");
|
|
14
|
+
|
|
15
|
+
var _Filename2 = _interopRequireDefault(_Filename);
|
|
16
|
+
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
|
|
19
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
20
|
+
|
|
21
|
+
var Order = function () {
|
|
22
|
+
function Order(data) {
|
|
23
|
+
_classCallCheck(this, Order);
|
|
24
|
+
|
|
25
|
+
var schema = {
|
|
26
|
+
_id: null,
|
|
27
|
+
asset: null,
|
|
28
|
+
project: null,
|
|
29
|
+
assetType: null,
|
|
30
|
+
country: null,
|
|
31
|
+
language: null,
|
|
32
|
+
dng: null
|
|
33
|
+
};
|
|
34
|
+
Object.assign(this, schema, data);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_createClass(Order, [{
|
|
38
|
+
key: "isDub",
|
|
39
|
+
value: function isDub() {
|
|
40
|
+
if (!this.dng) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return _lodash2.default.flattenDeep(Object.entries(this.dng)).includes("Dedicated / Localized");
|
|
44
|
+
}
|
|
45
|
+
}, {
|
|
46
|
+
key: "isSub",
|
|
47
|
+
value: function isSub() {
|
|
48
|
+
if (!this.dng) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return _lodash2.default.flattenDeep(Object.entries(this.dng)).includes("Subtitled");
|
|
52
|
+
}
|
|
53
|
+
}]);
|
|
54
|
+
|
|
55
|
+
return Order;
|
|
56
|
+
}();
|
|
57
|
+
|
|
58
|
+
exports.default = Order;
|
package/dist/src/Srt.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _lodash = require('lodash');
|
|
8
|
+
|
|
9
|
+
var _lodash2 = _interopRequireDefault(_lodash);
|
|
10
|
+
|
|
11
|
+
var _TimeFormat = require('./TimeFormat');
|
|
12
|
+
|
|
13
|
+
var _TimeFormat2 = _interopRequireDefault(_TimeFormat);
|
|
14
|
+
|
|
15
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
+
|
|
17
|
+
function stripTags(input, allowed) {
|
|
18
|
+
allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
|
|
19
|
+
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
|
|
20
|
+
var commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
|
21
|
+
return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
|
|
22
|
+
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var SRT_STATE_SUBNUMBER = 0,
|
|
27
|
+
SRT_STATE_TIME = 1,
|
|
28
|
+
SRT_STATE_TEXT = 2,
|
|
29
|
+
SRT_STATE_BLANK = 3;
|
|
30
|
+
|
|
31
|
+
exports.default = {
|
|
32
|
+
parse: function parse(lines) {
|
|
33
|
+
var result = [],
|
|
34
|
+
state = SRT_STATE_SUBNUMBER,
|
|
35
|
+
subText = '',
|
|
36
|
+
subTime = '';
|
|
37
|
+
|
|
38
|
+
function time(subTime) {
|
|
39
|
+
|
|
40
|
+
var range = subTime.split(' --> ');
|
|
41
|
+
if (!_TimeFormat2.default.isValidTime(range[0]) || !_TimeFormat2.default.isValidTime(range[1])) {
|
|
42
|
+
throw new Error('Malformed SRT file');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
startTime: range[0],
|
|
47
|
+
stopTime: range[1]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
lines.forEach(function (line) {
|
|
52
|
+
line = line.replace(/^\s+|\s+$/g, '');
|
|
53
|
+
|
|
54
|
+
switch (state) {
|
|
55
|
+
case SRT_STATE_SUBNUMBER:
|
|
56
|
+
state = SRT_STATE_TIME;
|
|
57
|
+
break;
|
|
58
|
+
|
|
59
|
+
case SRT_STATE_TIME:
|
|
60
|
+
subTime = line;
|
|
61
|
+
state = SRT_STATE_TEXT;
|
|
62
|
+
break;
|
|
63
|
+
|
|
64
|
+
case SRT_STATE_TEXT:
|
|
65
|
+
if (line !== '') {
|
|
66
|
+
subText += subText ? "\n" + line : line;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
result.push(Object.assign(time(subTime), {
|
|
70
|
+
text: subText
|
|
71
|
+
}));
|
|
72
|
+
subText = '';
|
|
73
|
+
state = SRT_STATE_SUBNUMBER;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
},
|
|
80
|
+
export: function _export(lines) {
|
|
81
|
+
var result = '',
|
|
82
|
+
i = 1;
|
|
83
|
+
|
|
84
|
+
lines.forEach(function (line) {
|
|
85
|
+
if (line.text === undefined) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Replace <br> tags with newlines. These tags may accidentally be stored in the translation
|
|
90
|
+
var text = _lodash2.default.unescape(line.text.replace(/<br>/g, '\n'));
|
|
91
|
+
|
|
92
|
+
// Remove any tags that may have made it into the translation (div tags seem to be the main problem).
|
|
93
|
+
// <b> <i> are the only two supported tags currently
|
|
94
|
+
text = stripTags(text, '<b><i>');
|
|
95
|
+
|
|
96
|
+
result += i++ + "\n";
|
|
97
|
+
result += _TimeFormat2.default.startTime(line) + " --> " + _TimeFormat2.default.stopTime(line) + "\n";
|
|
98
|
+
result += text + "\n\n";
|
|
99
|
+
});
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
};
|
package/dist/src/Sub.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = {
|
|
7
|
+
parse: function parse(lines) {
|
|
8
|
+
var result = [],
|
|
9
|
+
current = {
|
|
10
|
+
text: ""
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
lines.forEach(function (line) {
|
|
14
|
+
line = line.replace(/^\s+|\s+$/g, '');
|
|
15
|
+
var subTime = line.match(/^([0-9:\.]+),([0-9:\.]+)$/);
|
|
16
|
+
|
|
17
|
+
if (subTime) {
|
|
18
|
+
if (current.text) {
|
|
19
|
+
result.push(current);
|
|
20
|
+
}
|
|
21
|
+
current = {
|
|
22
|
+
startTime: subTime[1],
|
|
23
|
+
stopTime: subTime[2],
|
|
24
|
+
text: ""
|
|
25
|
+
};
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (line) {
|
|
30
|
+
if (current.startTime === undefined || current.stopTime === 'undefined') {
|
|
31
|
+
throw new Error('Malformed SUB file');
|
|
32
|
+
}
|
|
33
|
+
current.text += current.text ? "\n" + line : line;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (current.text) {
|
|
38
|
+
result.push(current);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var stringRegex = /^(\d+):(\d+):(\d+)[,|.](\d{2,3})?$/;
|
|
7
|
+
|
|
8
|
+
exports.default = {
|
|
9
|
+
isValidTime: function isValidTime(time) {
|
|
10
|
+
return !!time.match(stringRegex);
|
|
11
|
+
},
|
|
12
|
+
timeToTimestamp: function timeToTimestamp(time) {
|
|
13
|
+
var match = time.match(stringRegex);
|
|
14
|
+
if (!match) {
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
var precision = match[4].length === 2 ? 100 : 1000;
|
|
18
|
+
return parseInt(match[1], 10) * 60 * 60 + parseInt(match[2], 10) * 60 + parseInt(match[3], 10) + parseInt(match[4], 10) / precision;
|
|
19
|
+
},
|
|
20
|
+
timestampToTime: function timestampToTime(second, decimalMark) {
|
|
21
|
+
var hours = ~~(second / 3600);
|
|
22
|
+
var min = ~~(second / 60) % 60;
|
|
23
|
+
var sec = second % 60;
|
|
24
|
+
var fixedSec = sec.toFixed(3).replace('.', decimalMark ? decimalMark : ',');
|
|
25
|
+
return (hours < 10 ? '0' + hours : hours) + ":" + (min < 10 ? '0' + min : min) + ':' + (sec < 10 ? '0' + fixedSec : fixedSec);
|
|
26
|
+
},
|
|
27
|
+
timeDiff: function timeDiff(time1, time2) {
|
|
28
|
+
if (time1 === undefined || time2 === undefined) {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
return this.timestampDiff(this.timeToTimestamp(time1), this.timeToTimestamp(time2));
|
|
32
|
+
},
|
|
33
|
+
timestampDiff: function timestampDiff(time1, time2) {
|
|
34
|
+
if (time1 === undefined || time2 === undefined || time1 === time2) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
var diff = time2 - time1;
|
|
38
|
+
return Math.round(Math.max(-1, Math.min(1, diff)) * 10) / 10;
|
|
39
|
+
},
|
|
40
|
+
startTime: function startTime(line) {
|
|
41
|
+
var timestamp = this.timeToTimestamp(line.startTime) + (line.inOffset || 0);
|
|
42
|
+
return this.timestampToTime(timestamp);
|
|
43
|
+
},
|
|
44
|
+
stopTime: function stopTime(line) {
|
|
45
|
+
var timestamp = this.timeToTimestamp(line.stopTime) + (line.outOffset || 0);
|
|
46
|
+
return this.timestampToTime(timestamp);
|
|
47
|
+
}
|
|
48
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as Asset } from './src/Asset';
|
|
2
|
+
export { default as Filename } from './src/Filename';
|
|
3
|
+
export { default as Ingest } from './src/Ingest';
|
|
4
|
+
export { default as IngestFile } from './src/IngestFile';
|
|
5
|
+
export { default as IngestFileDrop } from './src/IngestFileDrop';
|
|
6
|
+
export { default as Order } from './src/Order';
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pixwel/pixwel-sdk",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"author": "Pixwel",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "babel -d dist index.js src/*.js",
|
|
10
|
+
"test": "jest --coverage"
|
|
11
|
+
},
|
|
12
|
+
"jest": {
|
|
13
|
+
"verbose": true,
|
|
14
|
+
"coverageDirectory": "coverage",
|
|
15
|
+
"collectCoverage": true,
|
|
16
|
+
"collectCoverageFrom": [
|
|
17
|
+
"src/*.js"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"babel-cli": "^6.26.0",
|
|
22
|
+
"babel-preset-env": "^1.7.0",
|
|
23
|
+
"jest": "^22.4.4",
|
|
24
|
+
"lodash": "^4.17.10"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/Ass.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import TimeFormat from './TimeFormat';
|
|
3
|
+
|
|
4
|
+
function trim(str) {
|
|
5
|
+
return str.replace(/^\s+|\s+$/g, '');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function searchIndex(lines, pattern, startIndex) {
|
|
9
|
+
var len = lines.length;
|
|
10
|
+
startIndex = startIndex || 0;
|
|
11
|
+
|
|
12
|
+
for (var i = startIndex; i < len; i++) {
|
|
13
|
+
var line = lines[i];
|
|
14
|
+
if (line.match(pattern)) {
|
|
15
|
+
return i;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function extractStyles(lines) {
|
|
22
|
+
var line, styles = {};
|
|
23
|
+
|
|
24
|
+
var currentIndex = searchIndex(lines, /^\[V4\+ Styles\]$/);
|
|
25
|
+
|
|
26
|
+
if (currentIndex === false) {
|
|
27
|
+
return styles;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
currentIndex = searchIndex(lines, /^Format:/, ++currentIndex);
|
|
31
|
+
|
|
32
|
+
if (currentIndex === false) {
|
|
33
|
+
return styles;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
line = trim(lines[currentIndex]);
|
|
37
|
+
var fields = line.replace(/^Format:\s+/, '').split(/\s*,\s*/);
|
|
38
|
+
var nameIndex = fields.indexOf('Name');
|
|
39
|
+
var alignmentIndex = fields.indexOf('Alignment');
|
|
40
|
+
|
|
41
|
+
if (nameIndex === -1) {
|
|
42
|
+
return styles;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var pattern = new RegExp('^' + (new Array(fields.length).join('\s*(.*?)\s*,')) + '(.*?)$');
|
|
46
|
+
|
|
47
|
+
currentIndex = searchIndex(lines, /^Style:/, ++currentIndex);
|
|
48
|
+
|
|
49
|
+
while (currentIndex !== false) {
|
|
50
|
+
line = trim(lines[currentIndex]);
|
|
51
|
+
|
|
52
|
+
var parts = line.replace(/^Style:\s+/, '').match(pattern);
|
|
53
|
+
if (!parts) {
|
|
54
|
+
throw new Error('Error, missing fields in a `Style` entry');
|
|
55
|
+
}
|
|
56
|
+
if (parts.length) {
|
|
57
|
+
var style = {};
|
|
58
|
+
if (alignmentIndex !== -1) {
|
|
59
|
+
var alignmentNumber = parts[alignmentIndex + 1];
|
|
60
|
+
style.alignment = alignmentNumber >= 7 ? 'top' : 'bottom';
|
|
61
|
+
}
|
|
62
|
+
styles[parts[nameIndex + 1]] = style;
|
|
63
|
+
}
|
|
64
|
+
currentIndex = searchIndex(lines, /^Style:/, ++currentIndex);
|
|
65
|
+
}
|
|
66
|
+
return styles;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default {
|
|
70
|
+
parse: function(lines) {
|
|
71
|
+
var line;
|
|
72
|
+
var currentIndex = 0;
|
|
73
|
+
|
|
74
|
+
function normalizeTime(time) {
|
|
75
|
+
if (time.charAt(1) === ':') {
|
|
76
|
+
time = '0' + time;
|
|
77
|
+
}
|
|
78
|
+
return time.replace('.', ',') + '0';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizeText(text) {
|
|
82
|
+
return text.replace(/\\n|\\N/, '\n')
|
|
83
|
+
.replace(/{\\(.*)1}(.*){\\\1[0]}/g, function(match, tag, content) {
|
|
84
|
+
return '<' + tag + '>' + content + '</' + tag + '>';
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var styles = extractStyles(lines);
|
|
89
|
+
|
|
90
|
+
currentIndex = searchIndex(lines, /^\[Events\]$/);
|
|
91
|
+
|
|
92
|
+
if (currentIndex === false) {
|
|
93
|
+
throw new Error('Error, missing `[Events]` section');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
currentIndex = searchIndex(lines, /^Format:/, ++currentIndex);
|
|
97
|
+
|
|
98
|
+
if (currentIndex === false) {
|
|
99
|
+
throw new Error('Error, missing `Format` entry');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
line = trim(lines[currentIndex]);
|
|
103
|
+
var fields = line.replace(/^Format:\s+/, '').split(/\s*,\s*/);
|
|
104
|
+
var startIndex = fields.indexOf('Start');
|
|
105
|
+
var endIndex = fields.indexOf('End');
|
|
106
|
+
var styleIndex = fields.indexOf('Style');
|
|
107
|
+
var textIndex = fields.indexOf('Text');
|
|
108
|
+
|
|
109
|
+
if (startIndex === -1 || endIndex === -1 || textIndex === -1) {
|
|
110
|
+
throw new Error('Error, missing fields in a `Format` entry');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var result = [];
|
|
114
|
+
var pattern = new RegExp('^' + (new Array(fields.length).join('\s*(.*?)\s*,')) + '(.*?)$');
|
|
115
|
+
|
|
116
|
+
currentIndex = searchIndex(lines, /^Dialogue:/, ++currentIndex);
|
|
117
|
+
|
|
118
|
+
while (currentIndex !== false) {
|
|
119
|
+
line = trim(lines[currentIndex]);
|
|
120
|
+
var parts = line.replace(/^Dialogue:\s+/, '').match(pattern);
|
|
121
|
+
if (!parts) {
|
|
122
|
+
throw new Error('Error, missing fields in a `Dialogue` entry');
|
|
123
|
+
}
|
|
124
|
+
if (parts.length) {
|
|
125
|
+
var entry = {
|
|
126
|
+
startTime: normalizeTime(parts[startIndex + 1]),
|
|
127
|
+
stopTime: normalizeTime(parts[endIndex + 1]),
|
|
128
|
+
text: normalizeText(parts[textIndex + 1]),
|
|
129
|
+
alignment: 'bottom'
|
|
130
|
+
};
|
|
131
|
+
if (styleIndex !== -1) {
|
|
132
|
+
var style = styles[parts[styleIndex + 1]];
|
|
133
|
+
if (style && style.alignment) {
|
|
134
|
+
entry.alignment = style.alignment;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
result.push(entry);
|
|
138
|
+
}
|
|
139
|
+
currentIndex = searchIndex(lines, /^Dialogue:/, ++currentIndex);
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
},
|
|
143
|
+
export: function(lines, options) {
|
|
144
|
+
var result = '';
|
|
145
|
+
|
|
146
|
+
options = options || {};
|
|
147
|
+
|
|
148
|
+
var font = options.font || {
|
|
149
|
+
face: 'Arial',
|
|
150
|
+
size: 20
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
result += "[Script Info]\n";
|
|
154
|
+
result += "ScriptType: v4.00+\n\n";
|
|
155
|
+
|
|
156
|
+
result += "[V4+ Styles]\n";
|
|
157
|
+
result += "Format: Name, Fontname, Fontsize, PrimaryColour,Shadow,MarginV,Alignment\n";
|
|
158
|
+
result += "Style: Bottom," + font.face + "," + font.size + ",&H00FFFFFF,1,20,2\n";
|
|
159
|
+
result += "Style: Top," + font.face + "," + font.size + ",&H00FFFFFF,1,20,8\n\n";
|
|
160
|
+
|
|
161
|
+
result += "[Events]\n";
|
|
162
|
+
result += "Format: Layer, Start, End, Style, Text\n";
|
|
163
|
+
|
|
164
|
+
function normalizeTime(time) {
|
|
165
|
+
if (time.charAt(0) === '0') {
|
|
166
|
+
time = time.substr(1);
|
|
167
|
+
}
|
|
168
|
+
return time.replace(',', '.').slice(0, -1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function normalizeText(text) {
|
|
172
|
+
return _.unescape(text
|
|
173
|
+
.replace(/<div>/g, '\\N')
|
|
174
|
+
.replace(/<\/div>/g, '')
|
|
175
|
+
.replace(/\n/g, '\\N')
|
|
176
|
+
.replace(/<br>/g, '\\N')
|
|
177
|
+
.replace(/<i>/g, '{\\i1}')
|
|
178
|
+
.replace(/<\/i>/g, '{\\i0}')
|
|
179
|
+
.replace(/<b>/g, '{\\b1}')
|
|
180
|
+
.replace(/<\/b>/g, '{\\b0}'))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
lines.forEach(function(line) {
|
|
184
|
+
if (line.text === undefined) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
result += "Dialogue: 0";
|
|
188
|
+
result += "," + normalizeTime(TimeFormat.startTime(line));
|
|
189
|
+
result += "," + normalizeTime(TimeFormat.stopTime(line));
|
|
190
|
+
result += line.alignment === 'top' ? ",Top" : ",Bottom";
|
|
191
|
+
result += "," + normalizeText(line.text) + "\n";
|
|
192
|
+
});
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
};
|
package/src/Asset.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default class Asset {
|
|
2
|
+
static mapFromOrder(order) {
|
|
3
|
+
if (!order) {
|
|
4
|
+
throw new Error("missing order");
|
|
5
|
+
}
|
|
6
|
+
if (!order.asset) {
|
|
7
|
+
throw new Error("missing order.asset");
|
|
8
|
+
}
|
|
9
|
+
if (!order.project) {
|
|
10
|
+
throw new Error("missing order.project");
|
|
11
|
+
}
|
|
12
|
+
if (!order.project.slug) {
|
|
13
|
+
throw new Error("missing order.project.slug");
|
|
14
|
+
}
|
|
15
|
+
var asset = order.asset;
|
|
16
|
+
asset.project = order.project;
|
|
17
|
+
asset.project.filePrefix = order.project.slug.toUpperCase();
|
|
18
|
+
return asset;
|
|
19
|
+
}
|
|
20
|
+
}
|