wavesurfer.js 7.12.6 → 7.12.8

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.
Files changed (73) hide show
  1. package/README.md +12 -6
  2. package/dist/__tests__/dom.test.js +17 -1
  3. package/dist/__tests__/drag-stream.test.d.ts +1 -0
  4. package/dist/__tests__/drag-stream.test.js +108 -0
  5. package/dist/__tests__/draggable.test.js +34 -0
  6. package/dist/__tests__/hover.test.d.ts +1 -0
  7. package/dist/__tests__/hover.test.js +64 -0
  8. package/dist/__tests__/regions.test.js +39 -0
  9. package/dist/__tests__/renderer.test.js +4 -0
  10. package/dist/__tests__/wavesurfer.test.js +13 -0
  11. package/dist/__tests__/webaudio.test.d.ts +1 -0
  12. package/dist/__tests__/webaudio.test.js +223 -0
  13. package/dist/dom.d.ts +5 -0
  14. package/dist/dom.js +12 -0
  15. package/dist/draggable.js +14 -4
  16. package/dist/fetcher.js +31 -10
  17. package/dist/fft.js +5 -1
  18. package/dist/player.d.ts +1 -0
  19. package/dist/player.js +13 -4
  20. package/dist/plugins/envelope.cjs +1 -1
  21. package/dist/plugins/envelope.esm.js +1 -1
  22. package/dist/plugins/envelope.js +1 -1
  23. package/dist/plugins/envelope.min.js +1 -1
  24. package/dist/plugins/hover.cjs +1 -1
  25. package/dist/plugins/hover.d.ts +2 -0
  26. package/dist/plugins/hover.esm.js +1 -1
  27. package/dist/plugins/hover.js +1 -1
  28. package/dist/plugins/hover.min.js +1 -1
  29. package/dist/plugins/minimap.cjs +1 -1
  30. package/dist/plugins/minimap.esm.js +1 -1
  31. package/dist/plugins/minimap.js +1 -1
  32. package/dist/plugins/minimap.min.js +1 -1
  33. package/dist/plugins/record.cjs +1 -1
  34. package/dist/plugins/record.esm.js +1 -1
  35. package/dist/plugins/record.js +1 -1
  36. package/dist/plugins/record.min.js +1 -1
  37. package/dist/plugins/regions.cjs +1 -1
  38. package/dist/plugins/regions.d.ts +1 -0
  39. package/dist/plugins/regions.esm.js +1 -1
  40. package/dist/plugins/regions.js +1 -1
  41. package/dist/plugins/regions.min.js +1 -1
  42. package/dist/plugins/spectrogram-windowed.cjs +1 -1
  43. package/dist/plugins/spectrogram-windowed.esm.js +1 -1
  44. package/dist/plugins/spectrogram-windowed.js +1 -1
  45. package/dist/plugins/spectrogram-windowed.min.js +1 -1
  46. package/dist/plugins/spectrogram.cjs +1 -1
  47. package/dist/plugins/spectrogram.esm.js +1 -1
  48. package/dist/plugins/spectrogram.js +1 -1
  49. package/dist/plugins/spectrogram.min.js +1 -1
  50. package/dist/plugins/timeline.cjs +1 -1
  51. package/dist/plugins/timeline.esm.js +1 -1
  52. package/dist/plugins/timeline.js +1 -1
  53. package/dist/plugins/timeline.min.js +1 -1
  54. package/dist/plugins/zoom.cjs +1 -1
  55. package/dist/plugins/zoom.d.ts +1 -0
  56. package/dist/plugins/zoom.esm.js +1 -1
  57. package/dist/plugins/zoom.js +1 -1
  58. package/dist/plugins/zoom.min.js +1 -1
  59. package/dist/reactive/drag-stream.js +14 -4
  60. package/dist/reactive/state-event-emitter.js +7 -0
  61. package/dist/renderer-utils.js +4 -2
  62. package/dist/renderer.d.ts +2 -0
  63. package/dist/renderer.js +23 -11
  64. package/dist/timer.js +1 -0
  65. package/dist/types.d.ts +18 -2
  66. package/dist/wavesurfer.cjs +1 -1
  67. package/dist/wavesurfer.d.ts +2 -0
  68. package/dist/wavesurfer.esm.js +1 -1
  69. package/dist/wavesurfer.js +35 -6
  70. package/dist/wavesurfer.min.js +1 -1
  71. package/dist/webaudio.d.ts +5 -0
  72. package/dist/webaudio.js +69 -6
  73. package/package.json +15 -14
package/dist/webaudio.js CHANGED
@@ -8,6 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import EventEmitter from './event-emitter.js';
11
+ function setWebAudioSessionPlayback() {
12
+ const navigator = globalThis.navigator;
13
+ if (!(navigator === null || navigator === void 0 ? void 0 : navigator.audioSession))
14
+ return;
15
+ try {
16
+ navigator.audioSession.type = 'playback';
17
+ }
18
+ catch (e) {
19
+ console.warn('Setting navigator.audioSession.type failed:', e);
20
+ }
21
+ }
11
22
  /**
12
23
  * A Web Audio buffer player emulating the behavior of an HTML5 Audio element.
13
24
  *
@@ -16,7 +27,7 @@ import EventEmitter from './event-emitter.js';
16
27
  * blob URL lifecycle management automatically.
17
28
  */
18
29
  class WebAudioPlayer extends EventEmitter {
19
- constructor(audioContext = new AudioContext()) {
30
+ constructor(audioContext) {
20
31
  super();
21
32
  this.bufferNode = null;
22
33
  this.playStartTime = 0;
@@ -34,7 +45,9 @@ class WebAudioPlayer extends EventEmitter {
34
45
  this.addEventListener = this.on;
35
46
  /** Unsubscribe from an event */
36
47
  this.removeEventListener = this.un;
37
- this.audioContext = audioContext;
48
+ this._destroyed = false;
49
+ setWebAudioSessionPlayback();
50
+ this.audioContext = audioContext || new AudioContext();
38
51
  this.gainNode = this.audioContext.createGain();
39
52
  this.gainNode.connect(this.audioContext.destination);
40
53
  }
@@ -43,6 +56,42 @@ class WebAudioPlayer extends EventEmitter {
43
56
  return;
44
57
  });
45
58
  }
59
+ /** For compatibility with HTMLMediaElement.remove(). Delegates to destroy(). */
60
+ remove() {
61
+ this.destroy();
62
+ }
63
+ /** Clean up all resources. Idempotent — safe to call multiple times. */
64
+ destroy() {
65
+ if (this._destroyed)
66
+ return;
67
+ this._destroyed = true;
68
+ // Clear currentSrc so any in-flight fetch/decode chains bail out
69
+ // via their existing `this.currentSrc !== value` guards
70
+ this.currentSrc = '';
71
+ // Stop and disconnect buffer node
72
+ if (this.bufferNode) {
73
+ this.bufferNode.onended = null;
74
+ try {
75
+ this.bufferNode.stop();
76
+ }
77
+ catch (_a) {
78
+ // Ignore InvalidStateError if node already stopped
79
+ }
80
+ this.bufferNode.disconnect();
81
+ this.bufferNode = null;
82
+ }
83
+ // Disconnect gain node
84
+ this.gainNode.disconnect();
85
+ // Close audio context (returns a promise, catch rejection if already closed)
86
+ // Guard with typeof check for mock environments where close may not exist
87
+ if (typeof this.audioContext.close === 'function') {
88
+ Promise.resolve(this.audioContext.close.call(this.audioContext)).catch(() => undefined);
89
+ }
90
+ // Clear buffer reference
91
+ this.buffer = null;
92
+ // Clear all event listeners
93
+ this.unAll();
94
+ }
46
95
  get src() {
47
96
  return this.currentSrc;
48
97
  }
@@ -103,16 +152,24 @@ class WebAudioPlayer extends EventEmitter {
103
152
  this.bufferNode.start(this.audioContext.currentTime, currentPos);
104
153
  this.playStartTime = this.audioContext.currentTime;
105
154
  this.bufferNode.onended = () => {
106
- if (this.currentTime >= this.duration) {
155
+ if (!this.paused && this.duration - this.currentTime < 0.01) {
107
156
  this.pause();
108
157
  this.emit('ended');
109
158
  }
110
159
  };
111
160
  }
112
161
  _pause() {
113
- var _a;
114
162
  this.paused = true;
115
- (_a = this.bufferNode) === null || _a === void 0 ? void 0 : _a.stop();
163
+ // Clear onended before stopping to prevent spurious 'ended' event
164
+ if (this.bufferNode) {
165
+ this.bufferNode.onended = null;
166
+ try {
167
+ this.bufferNode.stop();
168
+ }
169
+ catch (_a) {
170
+ // Ignore InvalidStateError if node already stopped
171
+ }
172
+ }
116
173
  this.playbackPosition += (this.audioContext.currentTime - this.playStartTime) * this._playbackRate;
117
174
  }
118
175
  play() {
@@ -130,13 +187,19 @@ class WebAudioPlayer extends EventEmitter {
130
187
  this.emit('pause');
131
188
  }
132
189
  stopAt(timeSeconds) {
133
- const delay = timeSeconds - this.currentTime;
190
+ // The stop is scheduled on the AudioContext clock, so convert the remaining
191
+ // media time to real time via the playback rate
192
+ const delay = (timeSeconds - this.currentTime) / this._playbackRate;
134
193
  const currentBufferNode = this.bufferNode;
135
194
  currentBufferNode === null || currentBufferNode === void 0 ? void 0 : currentBufferNode.stop(this.audioContext.currentTime + delay);
136
195
  currentBufferNode === null || currentBufferNode === void 0 ? void 0 : currentBufferNode.addEventListener('ended', () => {
137
196
  if (currentBufferNode === this.bufferNode) {
138
197
  this.bufferNode = null;
139
198
  this.pause();
199
+ // The 'ended' event fires with some latency, so clamp the reported
200
+ // position to the exact stop time
201
+ this.playbackPosition = Math.min(timeSeconds, this.duration);
202
+ this.emit('timeupdate');
140
203
  }
141
204
  }, { once: true });
142
205
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wavesurfer.js",
3
- "version": "7.12.6",
3
+ "version": "7.12.8",
4
4
  "license": "BSD-3-Clause",
5
5
  "author": "katspaugh",
6
6
  "description": "Audio waveform player",
@@ -64,32 +64,33 @@
64
64
  "make-plugin": "./scripts/plugin.sh",
65
65
  "cypress": "cypress open --e2e",
66
66
  "cypress:canary": "cypress open --e2e -b chrome:canary",
67
- "test": "cypress run --browser chrome",
67
+ "test": "cypress run --browser ${CYPRESS_BROWSER:-chromium}",
68
68
  "test:unit": "jest --coverage",
69
69
  "serve": "npx live-server --port=9090 --no-browser --ignore='.*,src,cypress,scripts'",
70
70
  "start": "npm run build:dev & npm run serve",
71
+ "dev": "npm run start",
71
72
  "prepare": "npm run build"
72
73
  },
73
74
  "packageManager": "yarn@1.22.22",
74
75
  "devDependencies": {
75
76
  "@rollup/plugin-terser": "^0.4.4",
76
- "@rollup/plugin-typescript": "^12.1.1",
77
+ "@rollup/plugin-typescript": "^12.3.0",
77
78
  "@types/jest": "^29.5.2",
78
- "@typescript-eslint/eslint-plugin": "^8.43.0",
79
- "@typescript-eslint/parser": "^8.43.0",
80
- "cypress": "^13.16.1",
79
+ "@typescript-eslint/eslint-plugin": "^8.60.1",
80
+ "@typescript-eslint/parser": "^8.60.1",
81
+ "cypress": "^13.17.0",
81
82
  "cypress-image-snapshot": "^4.0.1",
82
- "eslint": "^9.35.0",
83
+ "eslint": "^9.39.4",
83
84
  "eslint-config-prettier": "^9.1.0",
84
- "eslint-plugin-prettier": "^5.2.1",
85
- "glob": "^11.0.0",
85
+ "eslint-plugin-prettier": "^5.5.6",
86
+ "glob": "^11.1.0",
86
87
  "jest": "^29.7.0",
87
88
  "jest-environment-jsdom": "^29.7.0",
88
- "prettier": "^3.4.2",
89
- "rollup": "^4.50.1",
90
- "rollup-plugin-dts": "^6.1.0",
89
+ "prettier": "^3.8.3",
90
+ "rollup": "^4.61.1",
91
+ "rollup-plugin-dts": "^6.4.1",
91
92
  "rollup-plugin-web-worker-loader": "^1.7.0",
92
- "ts-jest": "^29.1.1",
93
- "typescript": "^5.9.2"
93
+ "ts-jest": "^29.4.11",
94
+ "typescript": "^5.9.3"
94
95
  }
95
96
  }