Changed SRT parser to a stream parser as well.
This commit is contained in:
@@ -134,57 +134,21 @@ addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
// Find the ASS or SRT track and load it
|
||||
var track = document.querySelector("#video > track[data-format='ass'], #video > track[data-format='srt']");
|
||||
switch (track.getAttribute("data-format")) {
|
||||
case "ass":
|
||||
libjass.ASS.fromUrl(track.src || track.getAttribute("src")).then(function (result) {
|
||||
debug("Script received.");
|
||||
libjass.ASS.fromUrl(track.src || track.getAttribute("src"), libjass.Format[track.getAttribute("data-format").toUpperCase()]).then(function (result) {
|
||||
debug("Script received.");
|
||||
|
||||
ass = result;
|
||||
ass = result;
|
||||
|
||||
if (libjass.debugMode) {
|
||||
// Export the ASS object for debugging
|
||||
window.ass = ass;
|
||||
}
|
||||
if (libjass.debugMode) {
|
||||
// Export the ASS object for debugging
|
||||
window.ass = ass;
|
||||
}
|
||||
|
||||
// Prepare the "Script resolution" option label
|
||||
document.querySelector("#script-resolution-label-width").appendChild(document.createTextNode(ass.properties.resolutionX));
|
||||
document.querySelector("#script-resolution-label-height").appendChild(document.createTextNode(ass.properties.resolutionY));
|
||||
// Prepare the "Script resolution" option label
|
||||
document.querySelector("#script-resolution-label-width").appendChild(document.createTextNode(ass.properties.resolutionX));
|
||||
document.querySelector("#script-resolution-label-height").appendChild(document.createTextNode(ass.properties.resolutionY));
|
||||
|
||||
// Test if everything is loaded
|
||||
testVideoAndASSLoaded();
|
||||
});
|
||||
break;
|
||||
|
||||
case "srt":
|
||||
var subsRequest = new XMLHttpRequest();
|
||||
subsRequest.open("GET", track.src || track.getAttribute("src"), true);
|
||||
subsRequest.addEventListener("load", function () {
|
||||
debug("Script received.");
|
||||
|
||||
if (libjass.debugMode) {
|
||||
console.time("Parsing ASS took");
|
||||
}
|
||||
|
||||
// Parse the response string into an ASS object
|
||||
libjass.ASS.fromString(subsRequest.responseText, libjass.Format[track.getAttribute("data-format").toUpperCase()]).then(function (result) {
|
||||
ass = result;
|
||||
|
||||
if (libjass.debugMode) {
|
||||
console.timeEnd("Parsing ASS took");
|
||||
|
||||
// Export the ASS object for debugging
|
||||
window.ass = ass;
|
||||
}
|
||||
|
||||
// Prepare the "Script resolution" option label
|
||||
document.querySelector("#script-resolution-label-width").appendChild(document.createTextNode(ass.properties.resolutionX));
|
||||
document.querySelector("#script-resolution-label-height").appendChild(document.createTextNode(ass.properties.resolutionY));
|
||||
|
||||
// Test if everything is loaded
|
||||
testVideoAndASSLoaded();
|
||||
});
|
||||
}, false);
|
||||
subsRequest.send(null);
|
||||
break;
|
||||
}
|
||||
// Test if everything is loaded
|
||||
testVideoAndASSLoaded();
|
||||
});
|
||||
}, false);
|
||||
|
||||
@@ -265,6 +265,125 @@ module libjass.parser {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parser that parses an {@link libjass.ASS} object from a {@link libjass.parser.Stream} of an SRT script.
|
||||
*
|
||||
* @param {!libjass.parser.Stream} stream The {@link libjass.parser.Stream} to parse
|
||||
*/
|
||||
export class SrtStreamParser {
|
||||
private _ass: ASS = new ASS();
|
||||
private _deferred: DeferredPromise<ASS> = new DeferredPromise<ASS>();
|
||||
|
||||
private _currentDialogueNumber: string = null;
|
||||
private _currentDialogueStart: string = null;
|
||||
private _currentDialogueEnd: string = null;
|
||||
private _currentDialogueText: string = null;
|
||||
|
||||
constructor(private _stream: Stream) {
|
||||
this._stream.nextLine().then(line => this._onNextLine(line));
|
||||
|
||||
this._ass.properties.resolutionX = 1280;
|
||||
this._ass.properties.resolutionY = 720;
|
||||
this._ass.properties.wrappingStyle = 1;
|
||||
this._ass.properties.scaleBorderAndShadow = true;
|
||||
|
||||
var newStyle = new Style(new Map<string, string>()
|
||||
.set("Name", "Default")
|
||||
.set("Italic", "0").set("Bold", "0").set("Underline", "0").set("StrikeOut", "0")
|
||||
.set("Fontname", "").set("Fontsize", "50")
|
||||
.set("ScaleX", "100").set("ScaleY", "100")
|
||||
.set("Spacing", "0")
|
||||
.set("Angle", "0")
|
||||
.set("PrimaryColour", "&H0000FFFF").set("SecondaryColour", "&H00000000").set("OutlineColour", "&H00000000").set("BackColour", "&H00000000")
|
||||
.set("Outline", "1").set("BorderStyle", "1")
|
||||
.set("Shadow", "1")
|
||||
.set("Alignment", "2")
|
||||
.set("MarginL", "80").set("MarginR", "80").set("MarginV", "35")
|
||||
);
|
||||
this._ass.styles.set(newStyle.name, newStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {!Promise.<!libjass.ASS>} A promise that will be resolved when the entire stream has been parsed.
|
||||
*/
|
||||
get ass(): Promise<ASS> {
|
||||
return this._deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} line
|
||||
*/
|
||||
private _onNextLine(line: string): void {
|
||||
if (line === null) {
|
||||
if (this._currentDialogueNumber !== null && this._currentDialogueStart !== null && this._currentDialogueEnd !== null && this._currentDialogueText !== null) {
|
||||
this._ass.dialogues.push(new Dialogue(new Map<string, string>()
|
||||
.set("Style", "Default")
|
||||
.set("Start", this._currentDialogueStart).set("End", this._currentDialogueEnd)
|
||||
.set("Layer", "0")
|
||||
.set("Text", this._currentDialogueText), this._ass)
|
||||
);
|
||||
}
|
||||
|
||||
this._deferred.resolve(this._ass);
|
||||
return;
|
||||
}
|
||||
|
||||
if (line[line.length - 1] === "\r") {
|
||||
line = line.substr(0, line.length - 1);
|
||||
}
|
||||
|
||||
if (line === "") {
|
||||
if (this._currentDialogueNumber !== null && this._currentDialogueStart !== null && this._currentDialogueEnd !== null && this._currentDialogueText !== null) {
|
||||
this._ass.dialogues.push(new Dialogue(new Map<string, string>()
|
||||
.set("Style", "Default")
|
||||
.set("Start", this._currentDialogueStart)
|
||||
.set("End", this._currentDialogueEnd)
|
||||
.set("Layer", "0")
|
||||
.set("Text", this._currentDialogueText), this._ass)
|
||||
);
|
||||
}
|
||||
|
||||
this._currentDialogueNumber = this._currentDialogueStart = this._currentDialogueEnd = this._currentDialogueText = null;
|
||||
}
|
||||
else {
|
||||
if (this._currentDialogueNumber === null) {
|
||||
if (/^\d+$/.test(line)) {
|
||||
this._currentDialogueNumber = line;
|
||||
}
|
||||
}
|
||||
else if (this._currentDialogueStart === null && this._currentDialogueEnd === null) {
|
||||
var match = /^(\d\d:\d\d:\d\d,\d\d\d) --> (\d\d:\d\d:\d\d,\d\d\d)/.exec(line);
|
||||
if (match !== null) {
|
||||
this._currentDialogueStart = match[1].replace(",", ".");
|
||||
this._currentDialogueEnd = match[2].replace(",", ".");
|
||||
}
|
||||
}
|
||||
else {
|
||||
line = line
|
||||
.replace(/<b>/g, "{\\b1}").replace(/\{b\}/g, "{\\b1}")
|
||||
.replace(/<\/b>/g, "{\\b0}").replace(/\{\/b\}/g, "{\\b0}")
|
||||
.replace(/<i>/g, "{\\i1}").replace(/\{i\}/g, "{\\i1}")
|
||||
.replace(/<\/i>/g, "{\\i0}").replace(/\{\/i\}/g, "{\\i0}")
|
||||
.replace(/<u>/g, "{\\u1}").replace(/\{u\}/g, "{\\u1}")
|
||||
.replace(/<\/u>/g, "{\\u0}").replace(/\{\/u\}/g, "{\\u0}")
|
||||
.replace(
|
||||
/<font color="#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})">/g,
|
||||
(/* ujs:unreferenced */ substring: string, red: string, green: string, blue: string) => "{\c&H" + blue + green + red + "&}"
|
||||
).replace(/<\/font>/g, "{\\c}");
|
||||
|
||||
if (this._currentDialogueText !== null) {
|
||||
this._currentDialogueText += "\\N" + line;
|
||||
}
|
||||
else {
|
||||
this._currentDialogueText = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._stream.nextLine().then(line => this._onNextLine(line));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a line into a {@link libjass.Property}.
|
||||
*
|
||||
@@ -2073,214 +2192,6 @@ module libjass.parser {
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!libjass.parser.ParseNode} parent
|
||||
* @return {libjass.parser.ParseNode}
|
||||
*/
|
||||
parse_srtScript(parent: ParseNode): ParseNode {
|
||||
var current = new ParseNode(parent);
|
||||
|
||||
current.value = [];
|
||||
|
||||
while (this._haveMore()) {
|
||||
var dialogueNode = this.parse_srtDialogue(current);
|
||||
if (dialogueNode === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
current.value.push(dialogueNode.value);
|
||||
|
||||
if (this.read(current, "\n") === null && this._haveMore()) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
while (this.read(current, "\n") !== null) { }
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!libjass.parser.ParseNode} parent
|
||||
* @return {libjass.parser.ParseNode}
|
||||
*/
|
||||
parse_srtDialogue(parent: ParseNode): ParseNode {
|
||||
var current = new ParseNode(parent);
|
||||
|
||||
current.value = Object.create(null);
|
||||
current.value.bounds = Object.create(null);
|
||||
current.value.bounds.x1 = null;
|
||||
current.value.bounds.y1 = null;
|
||||
current.value.bounds.x2 = null;
|
||||
current.value.bounds.y2 = null;
|
||||
|
||||
var numberNode = this.parse_unsignedDecimal(current);
|
||||
if (numberNode === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
current.value.number = parseInt(numberNode.value);
|
||||
|
||||
if (this.read(current, "\n") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var startTimeNode = this.parse_srtTime(current);
|
||||
if (startTimeNode === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
current.value.start = startTimeNode.value;
|
||||
|
||||
if (this.read(current, " --> ") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var endTimeNode = this.parse_srtTime(current);
|
||||
if (endTimeNode === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
current.value.end = endTimeNode.value;
|
||||
|
||||
if (this.read(current, " ") !== null) {
|
||||
var positionNode = new ParseNode(current, "");
|
||||
// TODO: Parse position properly into current.value.bounds
|
||||
for (var next = this._peek(); next !== "\n" && this._haveMore(); next = this._peek()) {
|
||||
positionNode.value += next;
|
||||
}
|
||||
current.value.bounds = positionNode.value;
|
||||
}
|
||||
|
||||
if (this.read(current, "\n") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var lineNode = new ParseNode(current, "");
|
||||
while (this._peek() !== "\n" && this._haveMore()) {
|
||||
var currentLine = "";
|
||||
for (var next = this._peek(); currentLine[currentLine.length - 1] !== "\n" && this._haveMore(); next = this._peek()) {
|
||||
currentLine += next;
|
||||
lineNode.value += next;
|
||||
}
|
||||
}
|
||||
|
||||
current.value.text = lineNode.value;
|
||||
if (current.value.text[current.value.text.length - 1] === "\n") {
|
||||
current.value.text = current.value.text.substr(0, current.value.text.length - 1);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!libjass.parser.ParseNode} parent
|
||||
* @return {libjass.parser.ParseNode}
|
||||
*/
|
||||
parse_srtTime(parent: ParseNode): ParseNode {
|
||||
var current = new ParseNode(parent);
|
||||
|
||||
var hourDigitNodes = new Array<ParseNode>(2);
|
||||
|
||||
for (var i = 0; i < hourDigitNodes.length; i++) {
|
||||
if (!this._haveMore()) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var next = this._peek();
|
||||
if (next >= "0" && next <= "9") {
|
||||
hourDigitNodes[i] = new ParseNode(current, next);
|
||||
}
|
||||
else {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.read(current, ":") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var minuteDigitNodes = new Array<ParseNode>(2);
|
||||
|
||||
for (i = 0; i < minuteDigitNodes.length; i++) {
|
||||
if (!this._haveMore()) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var next = this._peek();
|
||||
if (next >= "0" && next <= "9") {
|
||||
minuteDigitNodes[i] = new ParseNode(current, next);
|
||||
}
|
||||
else {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.read(current, ":") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var secondDigitNodes = new Array<ParseNode>(2);
|
||||
|
||||
for (i = 0; i < secondDigitNodes.length; i++) {
|
||||
if (!this._haveMore()) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var next = this._peek();
|
||||
if (next >= "0" && next <= "9") {
|
||||
secondDigitNodes[i] = new ParseNode(current, next);
|
||||
}
|
||||
else {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.read(current, ",") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var millisecondDigitNodes = new Array<ParseNode>(3);
|
||||
|
||||
for (i = 0; i < millisecondDigitNodes.length; i++) {
|
||||
if (!this._haveMore()) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
var next = this._peek();
|
||||
if (next >= "0" && next <= "9") {
|
||||
millisecondDigitNodes[i] = new ParseNode(current, next);
|
||||
}
|
||||
else {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
current.value =
|
||||
hourDigitNodes[0].value + hourDigitNodes[1].value + ":" +
|
||||
minuteDigitNodes[0].value + minuteDigitNodes[1].value + ":" +
|
||||
secondDigitNodes[0].value + secondDigitNodes[1].value + "." +
|
||||
millisecondDigitNodes[0].value + millisecondDigitNodes[1].value + millisecondDigitNodes[2].value;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!libjass.parser.ParseNode} parent
|
||||
* @param {string} next
|
||||
|
||||
+66
-24
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
var libjass = require("../libjass.js");
|
||||
var assert = require("assert");
|
||||
var parserTest = require("./parser-test.js");
|
||||
|
||||
suite("Miscellaneous", function () {
|
||||
@@ -157,29 +158,70 @@ suite("Miscellaneous", function () {
|
||||
new libjass.parts.Comment("p0")
|
||||
]);
|
||||
|
||||
parserTest("SRT", "1\n00:00:10,500 --> 00:00:13,000\nElephant's Dream\n\n2\n00:00:15,000 --> 00:00:18,000 X1:52 X2:303 Y1:438 Y2:453\n<font color=\"cyan\">At the left we can see...</font>", "srtScript", [{
|
||||
number: 1,
|
||||
start: "00:00:10.500", end: "00:00:13.000",
|
||||
bounds: { x1: null, y1: null, x2: null, y2: null },
|
||||
text: "Elephant's Dream"
|
||||
}, {
|
||||
number: 2,
|
||||
start: "00:00:15.000", end: "00:00:18.000",
|
||||
bounds: "X1:52 X2:303 Y1:438 Y2:453",
|
||||
text: "<font color=\"cyan\">At the left we can see...</font>"
|
||||
}
|
||||
]);
|
||||
test("SRT", function (done) {
|
||||
this.customProperties = {
|
||||
rule: "SRT",
|
||||
input: "1\n00:00:10,500 --> 00:00:13,000\nElephant's Dream\n\n2\n00:00:15,000 --> 00:00:18,000 X1:52 X2:303 Y1:438 Y2:453\n<font color=\"cyan\">At the left we can see...</font>"
|
||||
};
|
||||
|
||||
parserTest("SRT multiple lines", "1\n00:01:15,940 --> 00:01:17,280\nHave you secured the key?\nWhy can't people forgive each other\n\n2\n00:01:17,280 --> 00:01:17,670\nWhy can't people forgive each other", "srtScript", [{
|
||||
number: 1,
|
||||
start: "00:01:15.940", end: "00:01:17.280",
|
||||
bounds: { x1: null, y1: null, x2: null, y2: null },
|
||||
text: "Have you secured the key?\nWhy can't people forgive each other"
|
||||
}, {
|
||||
number: 2,
|
||||
start: "00:01:17.280", end: "00:01:17.670",
|
||||
bounds: { x1: null, y1: null, x2: null, y2: null },
|
||||
text: "Why can't people forgive each other"
|
||||
}
|
||||
]);
|
||||
libjass.ASS.fromString(this.customProperties.input, libjass.Format.SRT).then(function (ass) {
|
||||
try {
|
||||
assert.deepEqual(ass.dialogues.length, 2);
|
||||
|
||||
assert.deepEqual(ass.dialogues[0].start, 10.500);
|
||||
assert.deepEqual(ass.dialogues[0].end, 13.000);
|
||||
assert.deepEqual(ass.dialogues[0].parts, [
|
||||
new libjass.parts.Text("Elephant's Dream")
|
||||
]);
|
||||
|
||||
assert.deepEqual(ass.dialogues[1].start, 15.000);
|
||||
assert.deepEqual(ass.dialogues[1].end, 18.000);
|
||||
assert.deepEqual(ass.dialogues[1].parts, [
|
||||
new libjass.parts.Text("<font color=\"cyan\">At the left we can see..."),
|
||||
new libjass.parts.PrimaryColor(null)
|
||||
]);
|
||||
|
||||
done();
|
||||
}
|
||||
catch (ex) {
|
||||
done(ex);
|
||||
}
|
||||
}, function (reason) {
|
||||
done(reason);
|
||||
});
|
||||
});
|
||||
|
||||
test("SRT", function (done) {
|
||||
this.customProperties = {
|
||||
rule: "SRT",
|
||||
input: "1\n00:01:15,940 --> 00:01:17,280\nHave you secured the key?\nWhy can't people forgive each other\n\n2\n00:01:17,280 --> 00:01:17,670\nWhy can't people forgive each other"
|
||||
};
|
||||
|
||||
libjass.ASS.fromString(this.customProperties.input, libjass.Format.SRT).then(function (ass) {
|
||||
try {
|
||||
assert.deepEqual(ass.dialogues.length, 2);
|
||||
|
||||
assert.deepEqual(ass.dialogues[0].start, 1 * 60 + 15.940);
|
||||
assert.deepEqual(ass.dialogues[0].end, 1 * 60 + 17.280);
|
||||
assert.deepEqual(ass.dialogues[0].parts, [
|
||||
new libjass.parts.Text("Have you secured the key?"),
|
||||
new libjass.parts.NewLine(),
|
||||
new libjass.parts.Text("Why can't people forgive each other")
|
||||
]);
|
||||
|
||||
assert.deepEqual(ass.dialogues[1].start, 1 * 60 + 17.280);
|
||||
assert.deepEqual(ass.dialogues[1].end, 1 * 60 + 17.670);
|
||||
assert.deepEqual(ass.dialogues[1].parts, [
|
||||
new libjass.parts.Text("Why can't people forgive each other")
|
||||
]);
|
||||
|
||||
done();
|
||||
}
|
||||
catch (ex) {
|
||||
done(ex);
|
||||
}
|
||||
}, function (reason) {
|
||||
done(reason);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -157,35 +157,45 @@ module libjass {
|
||||
* @return {!Promise.<!libjass.ASS>}
|
||||
*/
|
||||
static fromString(raw: string, type: Format = Format.ASS): Promise<ASS> {
|
||||
switch (type) {
|
||||
case Format.ASS:
|
||||
return ASS.fromStream(new parser.StringStream(raw));
|
||||
case Format.SRT:
|
||||
return Promise.resolve(ASS._fromSRTString(raw));
|
||||
default:
|
||||
throw new Error("Illegal value of type: " + type);
|
||||
if ((<{ [index: string]: any }><any>Format)[Format[type]] !== type) {
|
||||
throw new Error("Illegal value of type: " + type);
|
||||
}
|
||||
|
||||
return ASS.fromStream(new parser.StringStream(raw), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given {@link libjass.parser.Stream}.
|
||||
*
|
||||
* @param {!libjass.parser.Stream} stream The stream to parse the script from
|
||||
* @param {number=0} type The type of the script. One of the {@link libjass.Format} constants.
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromStream(stream: parser.Stream): Promise<ASS> {
|
||||
return new parser.StreamParser(stream).ass;
|
||||
static fromStream(stream: parser.Stream, type: Format = Format.ASS): Promise<ASS> {
|
||||
switch (type) {
|
||||
case Format.ASS:
|
||||
return new parser.StreamParser(stream).ass;
|
||||
case Format.SRT:
|
||||
return new parser.SrtStreamParser(stream).ass;
|
||||
default:
|
||||
throw new Error("Illegal value of type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given URL.
|
||||
*
|
||||
* @param {string} url The URL of the script.
|
||||
* @param {number=0} type The type of the script. One of the {@link libjass.Format} constants.
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromUrl(url: string): Promise<ASS> {
|
||||
static fromUrl(url: string, type: Format = Format.ASS): Promise<ASS> {
|
||||
if ((<{ [index: string]: any }><any>Format)[Format[type]] !== type) {
|
||||
throw new Error("Illegal value of type: " + type);
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
var result = ASS.fromStream(new parser.XhrStream(xhr));
|
||||
var result = ASS.fromStream(new parser.XhrStream(xhr), type);
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user