@scarlett-player/embed 1.5.0 → 1.6.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.
- package/README.md +1 -1
- package/dist/embed.audio.js +304 -4
- package/dist/embed.audio.js.map +1 -1
- package/dist/embed.audio.umd.cjs +1 -1
- package/dist/embed.audio.umd.cjs.map +1 -1
- package/dist/embed.js +488 -56
- package/dist/embed.js.map +1 -1
- package/dist/embed.umd.cjs +1 -1
- package/dist/embed.umd.cjs.map +1 -1
- package/dist/embed.video.js +119 -3
- package/dist/embed.video.js.map +1 -1
- package/dist/embed.video.umd.cjs +1 -1
- package/dist/embed.video.umd.cjs.map +1 -1
- package/dist/hls2.js +12 -0
- package/dist/hls2.js.map +1 -0
- package/iframe.html +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
package/dist/embed.audio.js
CHANGED
|
@@ -180,8 +180,8 @@ class StateManager {
|
|
|
180
180
|
* Register a state key at runtime, for state a plugin owns.
|
|
181
181
|
*
|
|
182
182
|
* Core cannot know every plugin's keys, and {@link get} deliberately throws
|
|
183
|
-
* for unregistered ones
|
|
184
|
-
* keeping
|
|
183
|
+
* for unregistered ones - that throw is a useful typo-catcher and is worth
|
|
184
|
+
* keeping - so a plugin declares its keys before first use.
|
|
185
185
|
*
|
|
186
186
|
* Idempotent by design: re-defining an existing key leaves the current value
|
|
187
187
|
* untouched. Plugins commonly re-run setup after a source change, and that
|
|
@@ -1259,7 +1259,7 @@ class PluginAPI {
|
|
|
1259
1259
|
/**
|
|
1260
1260
|
* Register a state key this plugin owns, before first use.
|
|
1261
1261
|
*
|
|
1262
|
-
* Idempotent
|
|
1262
|
+
* Idempotent - re-defining an existing key keeps its current value.
|
|
1263
1263
|
* See {@link IPluginAPI.defineState}.
|
|
1264
1264
|
*
|
|
1265
1265
|
* @param key - State property key
|
|
@@ -4062,7 +4062,7 @@ function createAudioUIPlugin(config) {
|
|
|
4062
4062
|
if (layout === "mini") {
|
|
4063
4063
|
const wrapper = titleEl.parentElement;
|
|
4064
4064
|
if (wrapper && titleEl.scrollWidth > wrapper.clientWidth) {
|
|
4065
|
-
titleEl.textContent = `${title}
|
|
4065
|
+
titleEl.textContent = `${title} - ${title} - `;
|
|
4066
4066
|
titleEl.classList.add("scrolling");
|
|
4067
4067
|
} else {
|
|
4068
4068
|
titleEl.classList.remove("scrolling");
|
|
@@ -4220,6 +4220,272 @@ function createAudioUIPlugin(config) {
|
|
|
4220
4220
|
};
|
|
4221
4221
|
return plugin;
|
|
4222
4222
|
}
|
|
4223
|
+
var PLAYLIST_ICONS = {
|
|
4224
|
+
previous: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 6h2v12H6V6zm3.5 6L18 6v12l-8.5-6z"/></svg>',
|
|
4225
|
+
next: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M16 6h2v12h-2V6zM6 6l8.5 6L6 18V6z"/></svg>',
|
|
4226
|
+
list: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M3 6h11v2H3V6zm0 5h11v2H3v-2zm0 5h7v2H3v-2zm13-1.5V8l6 3.5-6 3.5z"/></svg>'
|
|
4227
|
+
};
|
|
4228
|
+
var PlaylistSkipButton = class {
|
|
4229
|
+
constructor(plugin, direction) {
|
|
4230
|
+
this.plugin = plugin;
|
|
4231
|
+
this.direction = direction;
|
|
4232
|
+
this.clickHandler = () => {
|
|
4233
|
+
if (this.direction === "next") {
|
|
4234
|
+
this.plugin.next();
|
|
4235
|
+
} else {
|
|
4236
|
+
this.plugin.previous();
|
|
4237
|
+
}
|
|
4238
|
+
};
|
|
4239
|
+
const label = direction === "next" ? "Next item" : "Previous item";
|
|
4240
|
+
this.el = document.createElement("button");
|
|
4241
|
+
this.el.type = "button";
|
|
4242
|
+
this.el.className = `sp-control sp-playlist-skip sp-playlist-skip--${direction}`;
|
|
4243
|
+
this.el.setAttribute("aria-label", label);
|
|
4244
|
+
this.el.setAttribute("title", label);
|
|
4245
|
+
this.el.innerHTML = PLAYLIST_ICONS[direction];
|
|
4246
|
+
this.el.addEventListener("click", this.clickHandler);
|
|
4247
|
+
}
|
|
4248
|
+
render() {
|
|
4249
|
+
return this.el;
|
|
4250
|
+
}
|
|
4251
|
+
update() {
|
|
4252
|
+
const state = this.plugin.getState();
|
|
4253
|
+
if (state.tracks.length <= 1) {
|
|
4254
|
+
this.el.style.display = "none";
|
|
4255
|
+
return;
|
|
4256
|
+
}
|
|
4257
|
+
this.el.style.display = "";
|
|
4258
|
+
const enabled = this.direction === "next" ? state.hasNext : state.hasPrevious;
|
|
4259
|
+
this.el.disabled = !enabled;
|
|
4260
|
+
}
|
|
4261
|
+
destroy() {
|
|
4262
|
+
this.el.removeEventListener("click", this.clickHandler);
|
|
4263
|
+
this.el.remove();
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
var PlaylistPanel = class {
|
|
4267
|
+
constructor(plugin, options) {
|
|
4268
|
+
this.plugin = plugin;
|
|
4269
|
+
this.options = options;
|
|
4270
|
+
this.open = false;
|
|
4271
|
+
this.renderedIds = "";
|
|
4272
|
+
this.toggleHandler = (event) => {
|
|
4273
|
+
event.stopPropagation();
|
|
4274
|
+
this.setOpen(!this.open);
|
|
4275
|
+
};
|
|
4276
|
+
this.documentClickHandler = () => {
|
|
4277
|
+
if (this.open) this.setOpen(false);
|
|
4278
|
+
};
|
|
4279
|
+
this.keydownHandler = (event) => {
|
|
4280
|
+
if (event.key === "Escape" && this.open) {
|
|
4281
|
+
this.setOpen(false);
|
|
4282
|
+
this.button.focus();
|
|
4283
|
+
}
|
|
4284
|
+
};
|
|
4285
|
+
this.el = document.createElement("div");
|
|
4286
|
+
this.el.className = "sp-playlist";
|
|
4287
|
+
this.button = document.createElement("button");
|
|
4288
|
+
this.button.type = "button";
|
|
4289
|
+
this.button.className = "sp-control sp-playlist__button";
|
|
4290
|
+
this.button.setAttribute("aria-label", "Playlist");
|
|
4291
|
+
this.button.setAttribute("title", "Playlist");
|
|
4292
|
+
this.button.setAttribute("aria-haspopup", "true");
|
|
4293
|
+
this.button.setAttribute("aria-expanded", "false");
|
|
4294
|
+
this.button.innerHTML = PLAYLIST_ICONS.list;
|
|
4295
|
+
this.panel = document.createElement("div");
|
|
4296
|
+
this.panel.className = "sp-playlist__panel";
|
|
4297
|
+
this.panel.setAttribute("role", "menu");
|
|
4298
|
+
this.panel.hidden = true;
|
|
4299
|
+
this.el.appendChild(this.button);
|
|
4300
|
+
this.el.appendChild(this.panel);
|
|
4301
|
+
this.button.addEventListener("click", this.toggleHandler);
|
|
4302
|
+
document.addEventListener("click", this.documentClickHandler);
|
|
4303
|
+
document.addEventListener("keydown", this.keydownHandler);
|
|
4304
|
+
}
|
|
4305
|
+
render() {
|
|
4306
|
+
return this.el;
|
|
4307
|
+
}
|
|
4308
|
+
update() {
|
|
4309
|
+
const state = this.plugin.getState();
|
|
4310
|
+
if (state.tracks.length <= 1) {
|
|
4311
|
+
this.el.style.display = "none";
|
|
4312
|
+
return;
|
|
4313
|
+
}
|
|
4314
|
+
this.el.style.display = "";
|
|
4315
|
+
const signature = state.tracks.map((track) => track.id).join("|");
|
|
4316
|
+
if (signature !== this.renderedIds) {
|
|
4317
|
+
this.renderedIds = signature;
|
|
4318
|
+
this.renderPanel(state.tracks, state.currentIndex);
|
|
4319
|
+
return;
|
|
4320
|
+
}
|
|
4321
|
+
this.markActive(state.currentIndex);
|
|
4322
|
+
}
|
|
4323
|
+
destroy() {
|
|
4324
|
+
this.button.removeEventListener("click", this.toggleHandler);
|
|
4325
|
+
document.removeEventListener("click", this.documentClickHandler);
|
|
4326
|
+
document.removeEventListener("keydown", this.keydownHandler);
|
|
4327
|
+
this.el.remove();
|
|
4328
|
+
}
|
|
4329
|
+
setOpen(open) {
|
|
4330
|
+
this.open = open;
|
|
4331
|
+
this.panel.hidden = !open;
|
|
4332
|
+
this.button.setAttribute("aria-expanded", String(open));
|
|
4333
|
+
this.el.classList.toggle("sp-playlist--open", open);
|
|
4334
|
+
}
|
|
4335
|
+
markActive(currentIndex) {
|
|
4336
|
+
const items = this.panel.querySelectorAll(".sp-playlist__item");
|
|
4337
|
+
items.forEach((item, index) => {
|
|
4338
|
+
item.classList.toggle("sp-playlist__item--active", index === currentIndex);
|
|
4339
|
+
item.setAttribute("aria-current", index === currentIndex ? "true" : "false");
|
|
4340
|
+
});
|
|
4341
|
+
}
|
|
4342
|
+
renderPanel(tracks, currentIndex) {
|
|
4343
|
+
this.panel.textContent = "";
|
|
4344
|
+
tracks.forEach((track, index) => {
|
|
4345
|
+
const item = document.createElement("button");
|
|
4346
|
+
item.type = "button";
|
|
4347
|
+
item.className = "sp-playlist__item";
|
|
4348
|
+
item.setAttribute("role", "menuitem");
|
|
4349
|
+
item.setAttribute("aria-current", index === currentIndex ? "true" : "false");
|
|
4350
|
+
if (index === currentIndex) {
|
|
4351
|
+
item.classList.add("sp-playlist__item--active");
|
|
4352
|
+
}
|
|
4353
|
+
const position = document.createElement("span");
|
|
4354
|
+
position.className = "sp-playlist__position";
|
|
4355
|
+
position.textContent = String(index + 1);
|
|
4356
|
+
const text = document.createElement("span");
|
|
4357
|
+
text.className = "sp-playlist__text";
|
|
4358
|
+
const title = document.createElement("span");
|
|
4359
|
+
title.className = "sp-playlist__title";
|
|
4360
|
+
title.textContent = track.title ?? `Item ${index + 1}`;
|
|
4361
|
+
text.appendChild(title);
|
|
4362
|
+
if (track.artist) {
|
|
4363
|
+
const artist = document.createElement("span");
|
|
4364
|
+
artist.className = "sp-playlist__artist";
|
|
4365
|
+
artist.textContent = track.artist;
|
|
4366
|
+
text.appendChild(artist);
|
|
4367
|
+
}
|
|
4368
|
+
item.appendChild(position);
|
|
4369
|
+
item.appendChild(text);
|
|
4370
|
+
item.addEventListener("click", (event) => {
|
|
4371
|
+
event.stopPropagation();
|
|
4372
|
+
this.options.onSelect(index);
|
|
4373
|
+
this.setOpen(false);
|
|
4374
|
+
});
|
|
4375
|
+
this.panel.appendChild(item);
|
|
4376
|
+
});
|
|
4377
|
+
}
|
|
4378
|
+
};
|
|
4379
|
+
var STYLE_ID = "sp-playlist-styles";
|
|
4380
|
+
var styles = `
|
|
4381
|
+
.sp-playlist-skip[disabled] {
|
|
4382
|
+
opacity: 0.4;
|
|
4383
|
+
cursor: default;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
.sp-playlist {
|
|
4387
|
+
position: relative;
|
|
4388
|
+
display: inline-flex;
|
|
4389
|
+
}
|
|
4390
|
+
|
|
4391
|
+
.sp-playlist__button svg,
|
|
4392
|
+
.sp-playlist-skip svg {
|
|
4393
|
+
width: 20px;
|
|
4394
|
+
height: 20px;
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
.sp-playlist__panel {
|
|
4398
|
+
position: absolute;
|
|
4399
|
+
bottom: calc(100% + 8px);
|
|
4400
|
+
right: 0;
|
|
4401
|
+
z-index: 20;
|
|
4402
|
+
display: flex;
|
|
4403
|
+
flex-direction: column;
|
|
4404
|
+
min-width: 240px;
|
|
4405
|
+
max-width: 320px;
|
|
4406
|
+
max-height: 300px;
|
|
4407
|
+
overflow-y: auto;
|
|
4408
|
+
padding: 4px;
|
|
4409
|
+
border-radius: 8px;
|
|
4410
|
+
background: rgba(20, 20, 20, 0.96);
|
|
4411
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
4412
|
+
}
|
|
4413
|
+
|
|
4414
|
+
.sp-playlist__panel[hidden] {
|
|
4415
|
+
display: none;
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4418
|
+
.sp-playlist__item {
|
|
4419
|
+
display: flex;
|
|
4420
|
+
gap: 10px;
|
|
4421
|
+
align-items: flex-start;
|
|
4422
|
+
width: 100%;
|
|
4423
|
+
padding: 8px 10px;
|
|
4424
|
+
border: 0;
|
|
4425
|
+
border-radius: 6px;
|
|
4426
|
+
background: transparent;
|
|
4427
|
+
color: #fff;
|
|
4428
|
+
font: inherit;
|
|
4429
|
+
text-align: left;
|
|
4430
|
+
cursor: pointer;
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
.sp-playlist__item:hover,
|
|
4434
|
+
.sp-playlist__item:focus-visible {
|
|
4435
|
+
background: rgba(255, 255, 255, 0.12);
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
.sp-playlist__item--active {
|
|
4439
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
.sp-playlist__item--active .sp-playlist__title {
|
|
4443
|
+
font-weight: 600;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
.sp-playlist__position {
|
|
4447
|
+
flex: 0 0 auto;
|
|
4448
|
+
min-width: 18px;
|
|
4449
|
+
color: rgba(255, 255, 255, 0.7);
|
|
4450
|
+
font-variant-numeric: tabular-nums;
|
|
4451
|
+
font-size: 12px;
|
|
4452
|
+
line-height: 18px;
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
.sp-playlist__text {
|
|
4456
|
+
display: flex;
|
|
4457
|
+
flex-direction: column;
|
|
4458
|
+
min-width: 0;
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4461
|
+
.sp-playlist__title {
|
|
4462
|
+
font-size: 13px;
|
|
4463
|
+
line-height: 18px;
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
.sp-playlist__artist {
|
|
4467
|
+
color: rgba(255, 255, 255, 0.6);
|
|
4468
|
+
font-size: 11px;
|
|
4469
|
+
line-height: 16px;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
@media (max-width: 480px) {
|
|
4473
|
+
.sp-playlist__panel {
|
|
4474
|
+
min-width: 200px;
|
|
4475
|
+
max-width: 76vw;
|
|
4476
|
+
}
|
|
4477
|
+
}
|
|
4478
|
+
`;
|
|
4479
|
+
function injectStyles() {
|
|
4480
|
+
if (typeof document === "undefined" || document.getElementById(STYLE_ID)) {
|
|
4481
|
+
return null;
|
|
4482
|
+
}
|
|
4483
|
+
const el = document.createElement("style");
|
|
4484
|
+
el.id = STYLE_ID;
|
|
4485
|
+
el.textContent = styles;
|
|
4486
|
+
document.head.appendChild(el);
|
|
4487
|
+
return el;
|
|
4488
|
+
}
|
|
4223
4489
|
var DEFAULT_CONFIG$1 = {
|
|
4224
4490
|
autoAdvance: true,
|
|
4225
4491
|
preloadNext: true,
|
|
@@ -4409,8 +4675,42 @@ function createPlaylistPlugin(config) {
|
|
|
4409
4675
|
api?.emit("playlist:ended", void 0);
|
|
4410
4676
|
}
|
|
4411
4677
|
});
|
|
4678
|
+
injectStyles();
|
|
4679
|
+
void import("./hls2.js").then(({ registerControl }) => {
|
|
4680
|
+
const self = plugin;
|
|
4681
|
+
registerControl(
|
|
4682
|
+
"playlist-previous",
|
|
4683
|
+
() => new PlaylistSkipButton(self, "previous")
|
|
4684
|
+
);
|
|
4685
|
+
registerControl("playlist-next", () => new PlaylistSkipButton(self, "next"));
|
|
4686
|
+
registerControl(
|
|
4687
|
+
"playlist",
|
|
4688
|
+
() => new PlaylistPanel(self, {
|
|
4689
|
+
onSelect: (index) => self.play(index)
|
|
4690
|
+
})
|
|
4691
|
+
);
|
|
4692
|
+
}).catch(() => {
|
|
4693
|
+
api?.logger.debug("@scarlett-player/ui not present, playlist controls not registered");
|
|
4694
|
+
});
|
|
4695
|
+
const onKeyDown = (event) => {
|
|
4696
|
+
if (!api || !api.container.contains(document.activeElement)) return;
|
|
4697
|
+
const activeEl = document.activeElement;
|
|
4698
|
+
if (activeEl instanceof HTMLInputElement || activeEl instanceof HTMLTextAreaElement || activeEl instanceof HTMLSelectElement || activeEl?.isContentEditable) {
|
|
4699
|
+
return;
|
|
4700
|
+
}
|
|
4701
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
4702
|
+
if (event.key === "n" || event.key === "N") {
|
|
4703
|
+
event.preventDefault();
|
|
4704
|
+
plugin.next();
|
|
4705
|
+
} else if (event.key === "p" || event.key === "P") {
|
|
4706
|
+
event.preventDefault();
|
|
4707
|
+
plugin.previous();
|
|
4708
|
+
}
|
|
4709
|
+
};
|
|
4710
|
+
document.addEventListener("keydown", onKeyDown);
|
|
4412
4711
|
api.onDestroy(() => {
|
|
4413
4712
|
unsubEnded();
|
|
4713
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
4414
4714
|
if (advanceTimeout) {
|
|
4415
4715
|
clearTimeout(advanceTimeout);
|
|
4416
4716
|
advanceTimeout = null;
|