roy-image-repository 0.1.1 → 0.1.2

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/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@ export declare class ImageRepository {
24
24
  private readonly videoUrl;
25
25
  private static _repositories;
26
26
  private _isInited;
27
+ private _isPlaying;
27
28
  private _videoElement?;
28
29
  /**
29
30
  * 视频DOM元素,使用它来渲染画布
@@ -35,11 +36,12 @@ export declare class ImageRepository {
35
36
  static getRepository(videoUrl: string): Promise<ImageRepository>;
36
37
  init(): Promise<void>;
37
38
  uninit(): void;
39
+ private _taskQueue;
38
40
  /**
39
- * 根据传入的微秒时间戳,获取指定位置的帧图片
41
+ * 根据传入的微秒时间戳,获取指定位置的帧图片,直接返回切换到对应帧的视频对象,在并发调用的情况下,内部通过统一的串行队列,将调用的结果按照顺序返回
40
42
  * @param timstampInMicroseconds 微秒时间戳
41
43
  */
42
- getImage(timstampInMicroseconds: number): Promise<void>;
44
+ getImage(timstampInMicroseconds: number): Promise<HTMLVideoElement>;
43
45
  /**
44
46
  * 开始播放连续帧图片
45
47
  */
@@ -1 +1 @@
1
- var royImageRepository=(function(s){"use strict";async function d(o){return new Promise((i,t)=>{const e=document.createElement("video");e.muted=!0,e.crossOrigin="anonymous",e.preload="metadata",e.onloadedmetadata=()=>{e.width=e.videoWidth,e.height=e.videoHeight,i(e)},e.onerror=r=>{console.log("video load error",r),t(r)},e.src=o})}function l(o){return{all:o=o||new Map,on:function(i,t){var e=o.get(i);e?e.push(t):o.set(i,[t])},off:function(i,t){var e=o.get(i);e&&(t?e.splice(e.indexOf(t)>>>0,1):o.set(i,[]))},emit:function(i,t){var e=o.get(i);e&&e.slice().map(function(r){r(t)}),(e=o.get("*"))&&e.slice().map(function(r){r(i,t)})}}}function a(o){return o/1e6}function m(o){return o*1e6}class n{constructor(i){this.videoUrl=i}static _repositories={};_isInited=!1;_videoElement;get videoElement(){if(!this._videoElement)throw new Error("image repository is not inited!");return this._videoElement}_requestVideoFrameCallbackId;_emitter=l();static async getRepository(i){const t=i.toLowerCase().trim();return this._repositories[t]||(this._repositories[t]=new n(t),await this._repositories[t].init()),this._repositories[t]}async init(){if(this._isInited)return;this._isInited=!0,this._videoElement=await d(this.videoUrl);const i=(t,e)=>{this._emitter.emit("requestFrame",{frameTimestampInMicroseconds:m(e.mediaTime),originalEvent:{now:t,metadata:e}}),this._requestVideoFrameCallbackId=this._videoElement.requestVideoFrameCallback(i)};this._requestVideoFrameCallbackId=this._videoElement.requestVideoFrameCallback(i)}uninit(){this._isInited&&(this._isInited=!1,this._requestVideoFrameCallbackId&&(this._videoElement.cancelVideoFrameCallback(this._requestVideoFrameCallbackId),this._requestVideoFrameCallbackId=void 0),this._videoElement=void 0,this._emitter.all.clear())}async getImage(i){if(!this._videoElement)throw new Error("image repository is not inited!");this._videoElement.currentTime=a(i)}async play(){if(!this._videoElement)throw new Error("image repository is not inited!");return await this._videoElement.play()}stop(){if(!this._videoElement)throw new Error("image repository is not inited!");this.pause(),this._videoElement.currentTime=a(0)}pause(){if(!this._videoElement)throw new Error("image repository is not inited!");this._videoElement.pause()}on(i,t){return this._emitter.on(i,t),{off:()=>{this._emitter.off(i,t)}}}}return s.ImageRepository=n,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"}),s})({});
1
+ var royImageRepository=(function(o){"use strict";async function u(r){return new Promise((e,t)=>{const i=document.createElement("video");i.muted=!0,i.crossOrigin="anonymous",i.preload="metadata",i.onloadedmetadata=()=>{i.width=i.videoWidth,i.height=i.videoHeight,e(i)},i.onerror=s=>{console.log("video load error",s),t(s)},i.src=r})}function l(r){return{all:r=r||new Map,on:function(e,t){var i=r.get(e);i?i.push(t):r.set(e,[t])},off:function(e,t){var i=r.get(e);i&&(t?i.splice(i.indexOf(t)>>>0,1):r.set(e,[]))},emit:function(e,t){var i=r.get(e);i&&i.slice().map(function(s){s(t)}),(i=r.get("*"))&&i.slice().map(function(s){s(e,t)})}}}function a(r){return r/1e6}function h(r){return r*1e6}class d{queue=[];running=!1;taskId=0;stopped=!1;enqueue(e){return this.stopped?Promise.reject(new Error("Queue has been stopped")):new Promise((t,i)=>{const s={id:++this.taskId,task:e,resolve:t,reject:i};this.queue.push(s),this.process()})}async process(){if(!this.running&&this.queue.length!==0){for(this.running=!0;this.queue.length>0;){const e=this.queue.shift();if(!e)break;try{const t=await e.task();e.resolve(t)}catch(t){e.reject(t)}}this.running=!1}}clear(e="Task cleared"){for(const t of this.queue)t.reject(new Error(e));this.queue=[]}stop(){this.stopped=!0,this.clear("Queue stopped")}isRunning(){return this.running}size(){return this.queue.length}}class n{constructor(e){this.videoUrl=e}static _repositories={};_isInited=!1;_isPlaying=!1;_videoElement;get videoElement(){if(!this._videoElement)throw new Error("image repository is not inited!");return this._videoElement}_requestVideoFrameCallbackId;_emitter=l();static getRepository(e){const t=e.toLowerCase().trim();return this._repositories[t]||(this._repositories[t]=(async()=>{const i=new n(t);return await i.init(),i})()),this._repositories[t]}async init(){this._isInited||(this._isInited=!0,this._videoElement=await u(this.videoUrl))}uninit(){this._isInited&&(this._isInited=!1,this._isPlaying&&this.stop(),this._taskQueue.stop(),this._videoElement=void 0,this._emitter.all.clear())}_taskQueue=new d;async getImage(e){return await this._taskQueue.enqueue(()=>new Promise((t,i)=>{if(!this._videoElement){i(new Error("image repository is not inited!"));return}if(this._isPlaying){i(new Error("image repository is playing!"));return}this._videoElement.requestVideoFrameCallback(()=>{t(this.videoElement)}),this._videoElement.currentTime=a(e)}))}async play(){if(!this._videoElement)throw new Error("image repository is not inited!");if(this._isPlaying)throw new Error("image repository is playing!");try{this._isPlaying=!0;const e=(t,i)=>{this._emitter.emit("requestFrame",{frameTimestampInMicroseconds:h(i.mediaTime),originalEvent:{now:t,metadata:i}}),this._requestVideoFrameCallbackId=this._videoElement.requestVideoFrameCallback(e)};return this._requestVideoFrameCallbackId=this._videoElement.requestVideoFrameCallback(e),await this._videoElement.play()}catch(e){throw this._isPlaying=!1,e}}stop(){if(!this._videoElement)throw new Error("image repository is not inited!");if(!this._isPlaying)throw new Error("image repository is not playing");this.pause(),this._videoElement.currentTime=a(0)}pause(){if(!this._videoElement)throw new Error("image repository is not inited!");if(!this._isPlaying)throw new Error("image repository is not playing");try{this._isPlaying=!1,this._requestVideoFrameCallbackId&&(this._videoElement.cancelVideoFrameCallback(this._requestVideoFrameCallbackId),this._requestVideoFrameCallbackId=void 0),this._videoElement.pause()}catch(e){throw this._isPlaying=!0,e}}on(e,t){return this._emitter.on(e,t),{off:()=>{this._emitter.off(e,t)}}}}return o.ImageRepository=n,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),o})({});
@@ -1,41 +1,106 @@
1
- async function a(o) {
2
- return new Promise((i, t) => {
3
- const e = document.createElement("video");
4
- e.muted = !0, e.crossOrigin = "anonymous", e.preload = "metadata", e.onloadedmetadata = () => {
5
- e.width = e.videoWidth, e.height = e.videoHeight, i(e);
6
- }, e.onerror = (r) => {
7
- console.log("video load error", r), t(r);
8
- }, e.src = o;
1
+ async function a(r) {
2
+ return new Promise((e, t) => {
3
+ const i = document.createElement("video");
4
+ i.muted = !0, i.crossOrigin = "anonymous", i.preload = "metadata", i.onloadedmetadata = () => {
5
+ i.width = i.videoWidth, i.height = i.videoHeight, e(i);
6
+ }, i.onerror = (s) => {
7
+ console.log("video load error", s), t(s);
8
+ }, i.src = r;
9
9
  });
10
10
  }
11
- function d(o) {
12
- return { all: o = o || /* @__PURE__ */ new Map(), on: function(i, t) {
13
- var e = o.get(i);
14
- e ? e.push(t) : o.set(i, [t]);
15
- }, off: function(i, t) {
16
- var e = o.get(i);
17
- e && (t ? e.splice(e.indexOf(t) >>> 0, 1) : o.set(i, []));
18
- }, emit: function(i, t) {
19
- var e = o.get(i);
20
- e && e.slice().map(function(r) {
21
- r(t);
22
- }), (e = o.get("*")) && e.slice().map(function(r) {
23
- r(i, t);
11
+ function u(r) {
12
+ return { all: r = r || /* @__PURE__ */ new Map(), on: function(e, t) {
13
+ var i = r.get(e);
14
+ i ? i.push(t) : r.set(e, [t]);
15
+ }, off: function(e, t) {
16
+ var i = r.get(e);
17
+ i && (t ? i.splice(i.indexOf(t) >>> 0, 1) : r.set(e, []));
18
+ }, emit: function(e, t) {
19
+ var i = r.get(e);
20
+ i && i.slice().map(function(s) {
21
+ s(t);
22
+ }), (i = r.get("*")) && i.slice().map(function(s) {
23
+ s(e, t);
24
24
  });
25
25
  } };
26
26
  }
27
- function s(o) {
28
- return o / 1e6;
27
+ function n(r) {
28
+ return r / 1e6;
29
29
  }
30
- function l(o) {
31
- return o * 1e6;
30
+ function l(r) {
31
+ return r * 1e6;
32
32
  }
33
- class n {
34
- constructor(i) {
35
- this.videoUrl = i;
33
+ class h {
34
+ queue = [];
35
+ running = !1;
36
+ taskId = 0;
37
+ stopped = !1;
38
+ /**
39
+ * 添加任务(泛型自动推导)
40
+ */
41
+ enqueue(e) {
42
+ return this.stopped ? Promise.reject(new Error("Queue has been stopped")) : new Promise((t, i) => {
43
+ const s = {
44
+ id: ++this.taskId,
45
+ task: e,
46
+ resolve: t,
47
+ reject: i
48
+ };
49
+ this.queue.push(s), this.process();
50
+ });
51
+ }
52
+ /**
53
+ * 串行执行核心逻辑
54
+ */
55
+ async process() {
56
+ if (!this.running && this.queue.length !== 0) {
57
+ for (this.running = !0; this.queue.length > 0; ) {
58
+ const e = this.queue.shift();
59
+ if (!e) break;
60
+ try {
61
+ const t = await e.task();
62
+ e.resolve(t);
63
+ } catch (t) {
64
+ e.reject(t);
65
+ }
66
+ }
67
+ this.running = !1;
68
+ }
69
+ }
70
+ /**
71
+ * 清空未执行任务
72
+ */
73
+ clear(e = "Task cleared") {
74
+ for (const t of this.queue)
75
+ t.reject(new Error(e));
76
+ this.queue = [];
77
+ }
78
+ /**
79
+ * 停止队列(不可恢复)
80
+ */
81
+ stop() {
82
+ this.stopped = !0, this.clear("Queue stopped");
83
+ }
84
+ /**
85
+ * 当前是否正在执行
86
+ */
87
+ isRunning() {
88
+ return this.running;
89
+ }
90
+ /**
91
+ * 当前等待数量
92
+ */
93
+ size() {
94
+ return this.queue.length;
95
+ }
96
+ }
97
+ class o {
98
+ constructor(e) {
99
+ this.videoUrl = e;
36
100
  }
37
101
  static _repositories = {};
38
102
  _isInited = !1;
103
+ _isPlaying = !1;
39
104
  _videoElement;
40
105
  /**
41
106
  * 视频DOM元素,使用它来渲染画布
@@ -46,36 +111,39 @@ class n {
46
111
  return this._videoElement;
47
112
  }
48
113
  _requestVideoFrameCallbackId;
49
- _emitter = d();
50
- static async getRepository(i) {
51
- const t = i.toLowerCase().trim();
52
- return this._repositories[t] || (this._repositories[t] = new n(t), await this._repositories[t].init()), this._repositories[t];
114
+ _emitter = u();
115
+ static getRepository(e) {
116
+ const t = e.toLowerCase().trim();
117
+ return this._repositories[t] || (this._repositories[t] = (async () => {
118
+ const i = new o(t);
119
+ return await i.init(), i;
120
+ })()), this._repositories[t];
53
121
  }
54
122
  async init() {
55
- if (this._isInited)
56
- return;
57
- this._isInited = !0, this._videoElement = await a(this.videoUrl);
58
- const i = (t, e) => {
59
- this._emitter.emit("requestFrame", {
60
- frameTimestampInMicroseconds: l(e.mediaTime),
61
- originalEvent: { now: t, metadata: e }
62
- }), this._requestVideoFrameCallbackId = this._videoElement.requestVideoFrameCallback(i);
63
- };
64
- this._requestVideoFrameCallbackId = this._videoElement.requestVideoFrameCallback(i);
123
+ this._isInited || (this._isInited = !0, this._videoElement = await a(this.videoUrl));
65
124
  }
66
125
  uninit() {
67
- this._isInited && (this._isInited = !1, this._requestVideoFrameCallbackId && (this._videoElement.cancelVideoFrameCallback(
68
- this._requestVideoFrameCallbackId
69
- ), this._requestVideoFrameCallbackId = void 0), this._videoElement = void 0, this._emitter.all.clear());
126
+ this._isInited && (this._isInited = !1, this._isPlaying && this.stop(), this._taskQueue.stop(), this._videoElement = void 0, this._emitter.all.clear());
70
127
  }
128
+ _taskQueue = new h();
71
129
  /**
72
- * 根据传入的微秒时间戳,获取指定位置的帧图片
130
+ * 根据传入的微秒时间戳,获取指定位置的帧图片,直接返回切换到对应帧的视频对象,在并发调用的情况下,内部通过统一的串行队列,将调用的结果按照顺序返回
73
131
  * @param timstampInMicroseconds 微秒时间戳
74
132
  */
75
- async getImage(i) {
76
- if (!this._videoElement)
77
- throw new Error("image repository is not inited!");
78
- this._videoElement.currentTime = s(i);
133
+ async getImage(e) {
134
+ return await this._taskQueue.enqueue(() => new Promise((t, i) => {
135
+ if (!this._videoElement) {
136
+ i(new Error("image repository is not inited!"));
137
+ return;
138
+ }
139
+ if (this._isPlaying) {
140
+ i(new Error("image repository is playing!"));
141
+ return;
142
+ }
143
+ this._videoElement.requestVideoFrameCallback(() => {
144
+ t(this.videoElement);
145
+ }), this._videoElement.currentTime = n(e);
146
+ }));
79
147
  }
80
148
  /**
81
149
  * 开始播放连续帧图片
@@ -83,7 +151,20 @@ class n {
83
151
  async play() {
84
152
  if (!this._videoElement)
85
153
  throw new Error("image repository is not inited!");
86
- return await this._videoElement.play();
154
+ if (this._isPlaying)
155
+ throw new Error("image repository is playing!");
156
+ try {
157
+ this._isPlaying = !0;
158
+ const e = (t, i) => {
159
+ this._emitter.emit("requestFrame", {
160
+ frameTimestampInMicroseconds: l(i.mediaTime),
161
+ originalEvent: { now: t, metadata: i }
162
+ }), this._requestVideoFrameCallbackId = this._videoElement.requestVideoFrameCallback(e);
163
+ };
164
+ return this._requestVideoFrameCallbackId = this._videoElement.requestVideoFrameCallback(e), await this._videoElement.play();
165
+ } catch (e) {
166
+ throw this._isPlaying = !1, e;
167
+ }
87
168
  }
88
169
  /**
89
170
  * 停止播放
@@ -91,7 +172,9 @@ class n {
91
172
  stop() {
92
173
  if (!this._videoElement)
93
174
  throw new Error("image repository is not inited!");
94
- this.pause(), this._videoElement.currentTime = s(0);
175
+ if (!this._isPlaying)
176
+ throw new Error("image repository is not playing");
177
+ this.pause(), this._videoElement.currentTime = n(0);
95
178
  }
96
179
  /**
97
180
  * 暂停播放
@@ -99,16 +182,24 @@ class n {
99
182
  pause() {
100
183
  if (!this._videoElement)
101
184
  throw new Error("image repository is not inited!");
102
- this._videoElement.pause();
185
+ if (!this._isPlaying)
186
+ throw new Error("image repository is not playing");
187
+ try {
188
+ this._isPlaying = !1, this._requestVideoFrameCallbackId && (this._videoElement.cancelVideoFrameCallback(
189
+ this._requestVideoFrameCallbackId
190
+ ), this._requestVideoFrameCallbackId = void 0), this._videoElement.pause();
191
+ } catch (e) {
192
+ throw this._isPlaying = !0, e;
193
+ }
103
194
  }
104
- on(i, t) {
105
- return this._emitter.on(i, t), {
195
+ on(e, t) {
196
+ return this._emitter.on(e, t), {
106
197
  off: () => {
107
- this._emitter.off(i, t);
198
+ this._emitter.off(e, t);
108
199
  }
109
200
  };
110
201
  }
111
202
  }
112
203
  export {
113
- n as ImageRepository
204
+ o as ImageRepository
114
205
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "roy-image-repository",
3
3
  "author": "roy",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "module": "./dist/roy-image-repository.js",
6
6
  "type": "module",
7
7
  "exports": {