@shotstack/shotstack-studio 2.14.3 → 2.15.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.
@@ -972,6 +972,37 @@ class ir extends J6 {
972
972
  const e = this.edit.playbackTime - this.getStart();
973
973
  return e < 0 ? 0 : e > this.getLength() ? this.getLength() : e;
974
974
  }
975
+ /**
976
+ * Playback speed of the asset (1 = normal). Matches `asset.speed` used by renders.
977
+ */
978
+ getAssetSpeed() {
979
+ const { speed: e = 1 } = this.clipConfiguration.asset;
980
+ return e;
981
+ }
982
+ /**
983
+ * Map clip playback time to source media time. Matches render output:
984
+ * sourceTime = speed × (trim + playbackTime), i.e. trim is also scaled by speed.
985
+ */
986
+ getSourceTime() {
987
+ const { trim: e = 0 } = this.clipConfiguration.asset;
988
+ return this.getAssetSpeed() * (e + this.getPlaybackTime());
989
+ }
990
+ /** Duration of the source media in seconds, or null when unknown or not applicable. */
991
+ getSourceDuration() {
992
+ return null;
993
+ }
994
+ /**
995
+ * Longest clip length the source media can fill at the current trim and speed
996
+ * (duration / speed − trim), or null when unbounded or the media isn't loaded yet.
997
+ */
998
+ getMaxLength() {
999
+ const e = this.getSourceDuration();
1000
+ if (e === null) return null;
1001
+ const r = this.getAssetSpeed();
1002
+ if (r <= 0) return null;
1003
+ const { trim: n = 0 } = this.clipConfiguration.asset;
1004
+ return Math.max(0.1, e / r - n);
1005
+ }
975
1006
  /**
976
1007
  * Returns the source content dimensions (before fit scaling).
977
1008
  */
@@ -1241,14 +1272,12 @@ class a_ extends ir {
1241
1272
  this.volumeKeyframeBuilder = new Jn(this.createVolumeKeyframes(e, s), this.getLength(), s), this.audioResource.volume(this.getVolume()), this.configureKeyframes();
1242
1273
  }
1243
1274
  update(e, r) {
1244
- super.update(e, r);
1245
- const { trim: n = 0 } = this.clipConfiguration.asset;
1246
- if (this.syncTimer += r, this.getContainer().alpha = 0, !this.audioResource)
1275
+ if (super.update(e, r), this.syncTimer += r, this.getContainer().alpha = 0, !this.audioResource)
1247
1276
  return;
1248
- const i = this.edit.isPlaying && this.isActive(), a = this.getPlaybackTime();
1249
- i && (this.isPlaying || (this.isPlaying = !0, this.audioResource.volume(this.getVolume()), this.audioResource.seek(a + n), this.audioResource.play()), this.audioResource.volume() !== this.getVolume() && this.audioResource.volume(this.getVolume()), Math.abs(this.audioResource.seek() - n - a) > 0.1 && this.audioResource.seek(a + n)), this.isPlaying && !i && (this.isPlaying = !1, this.audioResource.pause());
1277
+ const n = this.getAssetSpeed(), i = this.getSourceTime(), a = this.edit.isPlaying && this.isActive() && n > 0;
1278
+ a && (this.isPlaying || (this.isPlaying = !0, this.audioResource.volume(this.getVolume()), this.audioResource.rate(n), this.audioResource.seek(i), this.audioResource.play()), this.audioResource.volume() !== this.getVolume() && this.audioResource.volume(this.getVolume()), this.audioResource.rate() !== n && this.audioResource.rate(n), Math.abs(this.audioResource.seek() - i) > 0.1 && this.audioResource.seek(i)), this.isPlaying && !a && (this.isPlaying = !1, this.audioResource.pause());
1250
1279
  const s = this.syncTimer > 100;
1251
- !this.edit.isPlaying && this.isActive() && s && (this.syncTimer = 0, this.audioResource.seek(a + n));
1280
+ !this.edit.isPlaying && this.isActive() && s && (this.syncTimer = 0, this.audioResource.seek(i));
1252
1281
  }
1253
1282
  dispose() {
1254
1283
  this.audioResource && (this.audioResource.stop(), this.audioResource.unload()), this.audioResource = null, super.dispose();
@@ -1275,10 +1304,12 @@ class a_ extends ir {
1275
1304
  getVolume() {
1276
1305
  return this.volumeKeyframeBuilder.getValue(this.getPlaybackTime());
1277
1306
  }
1307
+ getSourceDuration() {
1308
+ const e = this.audioResource?.duration();
1309
+ return typeof e == "number" && e > 0 ? e : null;
1310
+ }
1278
1311
  getCurrentDrift() {
1279
- if (!this.audioResource) return 0;
1280
- const { trim: e = 0 } = this.clipConfiguration.asset, r = this.audioResource.seek(), n = this.getPlaybackTime();
1281
- return Math.abs(r - e - n);
1312
+ return this.audioResource ? Math.abs(this.audioResource.seek() - this.getSourceTime()) : 0;
1282
1313
  }
1283
1314
  createVolumeKeyframes(e, r) {
1284
1315
  const { effect: n, volume: i } = e;
@@ -38113,11 +38144,11 @@ const Yu = (t) => {
38113
38144
  provider: Ct("google-cloud-storage"),
38114
38145
  options: f(ZV)
38115
38146
  }).strict(), jV = _({
38116
- folderId: d(),
38147
+ folderId: f(d()),
38117
38148
  filename: f(d())
38118
38149
  }).strict(), GV = _({
38119
38150
  provider: Ct("google-drive"),
38120
- options: jV
38151
+ options: f(jV)
38121
38152
  }).strict(), WV = _({
38122
38153
  playbackPolicy: f(Vt($(["public", "signed"]))),
38123
38154
  passthrough: f(d().max(255))
@@ -41220,15 +41251,12 @@ class SR extends ir {
41220
41251
  this.clearPlaceholder(), this.placeholder = Do(e, r), this.contentContainer.addChild(this.placeholder), this.configureKeyframes();
41221
41252
  }
41222
41253
  update(e, r) {
41223
- if (super.update(e, r), this.skipVideoUpdate)
41254
+ if (super.update(e, r), this.skipVideoUpdate || (this.syncTimer += r, !this.texture))
41224
41255
  return;
41225
- const { trim: n = 0 } = this.clipConfiguration.asset;
41226
- if (this.syncTimer += r, !this.texture)
41227
- return;
41228
- const i = this.getPlaybackTime(), a = this.edit.isPlaying && this.isActive();
41229
- a && (this.isPlaying || (this.isPlaying = !0, this.activeSyncTimer = 0, this.texture.source.resource.volume = this.getVolume(), this.texture.source.resource.currentTime = i + n, this.texture.source.resource.play().catch(console.error)), this.texture.source.resource.volume !== this.getVolume() && (this.texture.source.resource.volume = this.getVolume()), this.activeSyncTimer += r, this.activeSyncTimer > 1e3 && (this.activeSyncTimer = 0, Math.abs(this.texture.source.resource.currentTime - n - i) > 0.3 && (this.texture.source.resource.currentTime = i + n))), !a && this.isPlaying && (this.isPlaying = !1, this.texture.source.resource.pause());
41256
+ const n = this.getAssetSpeed(), i = this.getSourceTime(), a = this.edit.isPlaying && this.isActive() && n > 0;
41257
+ a && (this.isPlaying || (this.isPlaying = !0, this.activeSyncTimer = 0, this.texture.source.resource.volume = this.getVolume(), this.texture.source.resource.currentTime = i, this.texture.source.resource.play().catch(console.error)), this.texture.source.resource.volume !== this.getVolume() && (this.texture.source.resource.volume = this.getVolume()), this.texture.source.resource.playbackRate !== n && (this.texture.source.resource.playbackRate = n), this.activeSyncTimer += r, this.activeSyncTimer > 1e3 && (this.activeSyncTimer = 0, Math.abs(this.texture.source.resource.currentTime - i) > 0.3 && (this.texture.source.resource.currentTime = i))), !a && this.isPlaying && (this.isPlaying = !1, this.texture.source.resource.pause());
41230
41258
  const s = this.syncTimer > 100;
41231
- !this.edit.isPlaying && this.isActive() && s && (this.syncTimer = 0, this.texture.source.resource.currentTime = i + n);
41259
+ (!this.edit.isPlaying || n === 0) && this.isActive() && s && (this.syncTimer = 0, this.texture.source.resource.currentTime = i);
41232
41260
  }
41233
41261
  dispose() {
41234
41262
  this.disposeVideo(), this.clearPlaceholder(), super.dispose();
@@ -41274,7 +41302,7 @@ class SR extends ir {
41274
41302
  s.removeEventListener("loadeddata", u), o();
41275
41303
  };
41276
41304
  s.addEventListener("loadeddata", u), s.readyState >= 2 && o();
41277
- }), this.sprite = new ot.Sprite(this.texture), this.contentContainer.addChild(this.sprite), this.texture.source.resource.volume = this.getVolume();
41305
+ }), this.sprite = new ot.Sprite(this.texture), this.contentContainer.addChild(this.sprite), this.texture.source.resource.volume = this.getVolume(), this.texture.source.resource.preservesPitch = !1;
41278
41306
  }
41279
41307
  disposeVideo() {
41280
41308
  this.texture?.source?.resource && (this.texture.source.resource.pause(), this.texture.source.resource.src = "", this.texture.source.resource.load()), this.sprite && (this.contentContainer.removeChild(this.sprite), this.sprite.destroy(), this.sprite = null), this.texture && (this.texture.destroy(!0), this.texture = null);
@@ -41285,10 +41313,12 @@ class SR extends ir {
41285
41313
  getVolume() {
41286
41314
  return this.volumeKeyframeBuilder.getValue(this.getPlaybackTime());
41287
41315
  }
41316
+ getSourceDuration() {
41317
+ const e = this.texture?.source?.resource?.duration;
41318
+ return typeof e == "number" && Number.isFinite(e) && e > 0 ? e : null;
41319
+ }
41288
41320
  getCurrentDrift() {
41289
- if (!this.texture?.source?.resource) return 0;
41290
- const { trim: e = 0 } = this.clipConfiguration.asset, r = this.texture.source.resource.currentTime, n = this.getPlaybackTime();
41291
- return Math.abs(r - e - n);
41321
+ return this.texture?.source?.resource ? Math.abs(this.texture.source.resource.currentTime - this.getSourceTime()) : 0;
41292
41322
  }
41293
41323
  createCroppedTexture(e) {
41294
41324
  const r = this.clipConfiguration.asset;