mirror of
https://github.com/zoriya/libpgs-js.git
synced 2026-08-27 00:00:51 +00:00
Added a ready promise to await the subtitle file being loaded
This commit is contained in:
@@ -66,6 +66,14 @@ const pgsRenderer = new libpgs.PgsRenderer({
|
||||
});
|
||||
```
|
||||
|
||||
### Awaiting the subtitle
|
||||
|
||||
`ready` resolves once the subtitle file can be rendered, and every `loadFrom*` call returns that same promise:
|
||||
|
||||
```javascript
|
||||
await pgsRenderer.ready;
|
||||
```
|
||||
|
||||
### Time offset
|
||||
|
||||
You can also adjust time offset between video and subtitle:
|
||||
|
||||
+14
-5
@@ -47,7 +47,9 @@ export class PgsRenderer {
|
||||
this.aspectRatio = options.aspectRatio;
|
||||
}
|
||||
if (options.subUrl) {
|
||||
this.loadFromUrl(options.subUrl);
|
||||
// A failed load is reported through `ready`. It is handled here too,
|
||||
// or callers that never await it would get an unhandled rejection.
|
||||
this.loadFromUrl(options.subUrl).catch(() => {});
|
||||
}
|
||||
|
||||
this.registerVideoEvents();
|
||||
@@ -72,20 +74,27 @@ export class PgsRenderer {
|
||||
|
||||
private implementation: PgsRendererImpl;
|
||||
|
||||
/**
|
||||
* Resolves once the last loaded subtitle file - `subUrl` included - can be rendered.
|
||||
*/
|
||||
public ready: Promise<void> = Promise.resolve();
|
||||
|
||||
/**
|
||||
* Loads the subtitle file from the given url.
|
||||
* @param url The url to the PGS file.
|
||||
*/
|
||||
public loadFromUrl(url: string): void {
|
||||
this.implementation.loadFromUrl(url);
|
||||
public loadFromUrl(url: string): Promise<void> {
|
||||
this.ready = this.implementation.loadFromUrl(url);
|
||||
return this.ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the subtitle file from the given buffer.
|
||||
* @param buffer The PGS data.
|
||||
*/
|
||||
public loadFromBuffer(buffer: ArrayBuffer): void {
|
||||
this.implementation.loadFromBuffer(buffer);
|
||||
public loadFromBuffer(buffer: ArrayBuffer): Promise<void> {
|
||||
this.ready = this.implementation.loadFromBuffer(buffer);
|
||||
return this.ready;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,13 +61,13 @@ export abstract class PgsRendererImpl {
|
||||
* Loads the subtitle file from the given url.
|
||||
* @param url The url to the PGS file.
|
||||
*/
|
||||
public abstract loadFromUrl(url: string): void;
|
||||
public abstract loadFromUrl(url: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Loads the subtitle file from the given buffer.
|
||||
* @param buffer The PGS data.
|
||||
*/
|
||||
public abstract loadFromBuffer(buffer: ArrayBuffer): void;
|
||||
public abstract loadFromBuffer(buffer: ArrayBuffer): Promise<void>;
|
||||
|
||||
/**
|
||||
* Disposes the renderer.
|
||||
|
||||
@@ -35,8 +35,8 @@ export class PgsRendererInMainThread extends PgsRendererImpl {
|
||||
this.pgs.cacheSubtitleAtIndex(index + 1);
|
||||
}
|
||||
|
||||
public loadFromUrl(url: string): void {
|
||||
this.pgs.loadFromUrl(url, {
|
||||
public loadFromUrl(url: string): Promise<void> {
|
||||
return this.pgs.loadFromUrl(url, {
|
||||
onProgress: () => {
|
||||
this.invokeTimestampsUpdate();
|
||||
}
|
||||
@@ -45,8 +45,8 @@ export class PgsRendererInMainThread extends PgsRendererImpl {
|
||||
});
|
||||
}
|
||||
|
||||
public loadFromBuffer(buffer: ArrayBuffer): void {
|
||||
this.pgs.loadFromBuffer(buffer).then(() => {
|
||||
public loadFromBuffer(buffer: ArrayBuffer): Promise<void> {
|
||||
return this.pgs.loadFromBuffer(buffer).then(() => {
|
||||
this.invokeTimestampsUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,18 +15,20 @@ export abstract class PgsRendererInWorker extends PgsRendererImpl {
|
||||
this.worker.onmessage = this.$onWorkerMessage;
|
||||
}
|
||||
|
||||
public loadFromUrl(url: string): void {
|
||||
public loadFromUrl(url: string): Promise<void> {
|
||||
this.worker.postMessage({
|
||||
op: 'loadFromUrl',
|
||||
url: url,
|
||||
});
|
||||
return new Promise((resolve, reject) => this.pendingLoads.push({resolve: resolve, reject: reject}));
|
||||
}
|
||||
|
||||
public loadFromBuffer(buffer: ArrayBuffer): void {
|
||||
public loadFromBuffer(buffer: ArrayBuffer): Promise<void> {
|
||||
this.worker.postMessage({
|
||||
op: 'loadFromBuffer',
|
||||
buffer: buffer,
|
||||
});
|
||||
return new Promise((resolve, reject) => this.pendingLoads.push({resolve: resolve, reject: reject}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,6 +36,11 @@ export abstract class PgsRendererInWorker extends PgsRendererImpl {
|
||||
*/
|
||||
protected readonly worker: Worker;
|
||||
|
||||
/**
|
||||
* The loads the worker still has to answer, in the order it answers them.
|
||||
*/
|
||||
private readonly pendingLoads: { resolve: () => void, reject: (error: Error) => void }[] = [];
|
||||
|
||||
/**
|
||||
* Handles messages from the worker.
|
||||
* @param e The event message.
|
||||
@@ -53,6 +60,17 @@ export abstract class PgsRendererInWorker extends PgsRendererImpl {
|
||||
this.setUpdateTimestamps(e.data.updateTimestamps);
|
||||
break;
|
||||
}
|
||||
|
||||
// Is called once a subtitle file was fully loaded, or failed to load.
|
||||
case 'loaded': {
|
||||
const pending = this.pendingLoads.shift();
|
||||
if (e.data.error) {
|
||||
pending?.reject(new Error(e.data.error));
|
||||
} else {
|
||||
pending?.resolve();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,5 +79,9 @@ export abstract class PgsRendererInWorker extends PgsRendererImpl {
|
||||
*/
|
||||
public dispose(): void {
|
||||
this.worker.terminate();
|
||||
// No answer is coming anymore, and being disposed is not a load failure.
|
||||
for (const pending of this.pendingLoads) {
|
||||
pending.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,14 @@ const submitTimestamps = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// Inform the main process that the subtitle file was fully loaded, or failed to load.
|
||||
const submitLoaded = (error?: string) => {
|
||||
postMessage({
|
||||
op: 'loaded',
|
||||
error: error
|
||||
})
|
||||
}
|
||||
|
||||
// Handles messages from the main thread.
|
||||
onmessage = (e: MessageEvent) => {
|
||||
switch (e.data.op) {
|
||||
@@ -41,6 +49,9 @@ onmessage = (e: MessageEvent) => {
|
||||
}
|
||||
}).then(() => {
|
||||
submitTimestamps();
|
||||
submitLoaded();
|
||||
}).catch((e: unknown) => {
|
||||
submitLoaded(`${e}`);
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -50,6 +61,9 @@ onmessage = (e: MessageEvent) => {
|
||||
const buffer: ArrayBuffer = e.data.buffer;
|
||||
pgs.loadFromBuffer(buffer).then(() => {
|
||||
submitTimestamps();
|
||||
submitLoaded();
|
||||
}).catch((e: unknown) => {
|
||||
submitLoaded(`${e}`);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "@tsconfig/recommended/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["ES2015", "DOM"],
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
Reference in New Issue
Block a user