@tidal-music/player-web-components 0.2.1 → 0.3.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/dist/active-device-changed-BDbOSq7P-DQ6vFR_K.js +7 -0
- package/dist/active-device-mode-changed-OmLVES_4-zwN5exje.js +7 -0
- package/dist/audio-context-store-Bf50rcqa-DUuCXOzU.js +36 -0
- package/dist/basePlayer-D9LFxFnB-BNIKxMHD.js +380 -0
- package/dist/browserPlayer-BzBNrx-C-DjxeaFTq.js +170 -0
- package/dist/generate-guid-BMGZjV-R-D16yCCHx.js +1716 -0
- package/dist/index.js +368 -10
- package/dist/load-L6Urw8gV-CQAMBwcN.js +29443 -0
- package/dist/media-element-error-circuit-breaker-BUJbK6sd-DNlFckiw.js +22 -0
- package/dist/nativePlayer-DtYpfmo5-nNN5yO4E.js +232 -0
- package/dist/output-devices-CPJfYcO--BP7JMB6k.js +156 -0
- package/dist/pushkin-C7W2HCqN-BHqS8oLX.js +117 -0
- package/dist/pushkin-dg1sQNx0-CAPg-zq7.js +2 -0
- package/dist/shakaPlayer-CqIY64ST-BhwOXSvi.js +1448 -0
- package/dist/src/helpers.d.ts +18 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/tidal-current-time.d.ts +9 -0
- package/dist/src/tidal-duration-time.d.ts +9 -0
- package/dist/src/tidal-play-trigger.d.ts +2 -0
- package/dist/src/tidal-progress-bar.d.ts +2 -0
- package/dist/src/tidal-video-view.d.ts +2 -0
- package/dist/state-BT7sE_jc-iVaBwnBC.js +210 -0
- package/package.json +15 -13
- package/dist/_commonjsHelpers-DaMA6jEr-DtILRGNx.js +0 -8
- package/dist/basePlayer-Rqi9yRuo-4eKn-Akv.js +0 -528
- package/dist/browserPlayer-CXURpXdL-DjOb2ySS.js +0 -259
- package/dist/index-DHnVYeec.js +0 -3391
- package/dist/index.d.ts +0 -24
- package/dist/nativePlayer-b92CavhC-CABrQPGS.js +0 -323
- package/dist/output-devices-CUurcKto-C_F_9nLk.js +0 -224
- package/dist/shakaPlayer-D0NCOzx8-Dd1YFBoR.js +0 -24403
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { a as e, n as t } from "./state-BT7sE_jc-iVaBwnBC.js";
|
|
2
|
+
import { t as n } from "./pushkin-C7W2HCqN-BHqS8oLX.js";
|
|
3
|
+
//#region ../player/dist/media-element-error-circuit-breaker-BUJbK6sd.js
|
|
4
|
+
var r = 6e4, i = (e) => {
|
|
5
|
+
console.error("HTMLMediaElement errored", e.target?.error ?? null);
|
|
6
|
+
}, a = () => {
|
|
7
|
+
console.error("HTMLMediaElement error limit reached, suppressing further errors"), e.dispatchError(new t("EUnexpected", "ME01"));
|
|
8
|
+
};
|
|
9
|
+
function o(e = {}) {
|
|
10
|
+
let { errorWindowMs: t = r, log: o = i, maxErrors: s = 10, now: c = () => n.now(), onLimitReached: l = a } = e, u = 0, d = 0;
|
|
11
|
+
return {
|
|
12
|
+
handleError(e) {
|
|
13
|
+
let n = c();
|
|
14
|
+
n - d >= t && (u = 0), d = n, u += 1, u <= s && o(e), u === s && l();
|
|
15
|
+
},
|
|
16
|
+
reset() {
|
|
17
|
+
u = 0, d = 0;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { o as t };
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { a as e, i as t, n, t as r, u as i } from "./state-BT7sE_jc-iVaBwnBC.js";
|
|
2
|
+
import { t as a } from "./pushkin-C7W2HCqN-BHqS8oLX.js";
|
|
3
|
+
import { a as o } from "./load-L6Urw8gV-CQAMBwcN.js";
|
|
4
|
+
import { t as s } from "./active-device-mode-changed-OmLVES_4-zwN5exje.js";
|
|
5
|
+
import { t as c } from "./active-device-changed-BDbOSq7P-DQ6vFR_K.js";
|
|
6
|
+
import { n as l, r as u, t as d } from "./basePlayer-D9LFxFnB-BNIKxMHD.js";
|
|
7
|
+
//#region ../player/dist/nativePlayer-DtYpfmo5.js
|
|
8
|
+
var f = "active-device-disconnected";
|
|
9
|
+
function p() {
|
|
10
|
+
return new CustomEvent(f);
|
|
11
|
+
}
|
|
12
|
+
var m = {
|
|
13
|
+
file_checksum_mismatch: "NPO02",
|
|
14
|
+
no_such_file: "NPO01",
|
|
15
|
+
unreadable_file: "NPO03"
|
|
16
|
+
}, h = {
|
|
17
|
+
devicedisconnected: "NPD01",
|
|
18
|
+
deviceexclusivemodenotallowed: "NPD02",
|
|
19
|
+
deviceformatnotsupported: "NPD03",
|
|
20
|
+
devicelocked: "NPD04",
|
|
21
|
+
devicenotfound: "NPD05",
|
|
22
|
+
deviceunknownerror: "NPD00"
|
|
23
|
+
}, g, _ = class extends d {
|
|
24
|
+
#e = "default";
|
|
25
|
+
#t;
|
|
26
|
+
#n;
|
|
27
|
+
#r;
|
|
28
|
+
name = "nativePlayer";
|
|
29
|
+
playbackEngineHandlerAttached = !1;
|
|
30
|
+
constructor() {
|
|
31
|
+
super(), i("outputDevicesEnabled") && (async () => {
|
|
32
|
+
g = (await import("./output-devices-CPJfYcO--BP7JMB6k.js")).outputDevices, this.#n.listDevices();
|
|
33
|
+
})(), this.#n = window.NativePlayerComponent.Player(), this.playbackState = "IDLE", this.registerEventListeners(), this.#n.setVolume(100);
|
|
34
|
+
}
|
|
35
|
+
#i(t) {
|
|
36
|
+
e.dispatchError(new n("EUnexpected", h[t]));
|
|
37
|
+
}
|
|
38
|
+
#a(t) {
|
|
39
|
+
this.debugLog("handleMediaError", t.target);
|
|
40
|
+
let r = m[t.target.errorCode];
|
|
41
|
+
this.currentStreamingSessionId && o({
|
|
42
|
+
errorCode: r,
|
|
43
|
+
errorMessage: JSON.stringify(t.target),
|
|
44
|
+
streamingSessionId: this.currentStreamingSessionId
|
|
45
|
+
}), e.dispatchError(new n("EUnexpected", r));
|
|
46
|
+
}
|
|
47
|
+
#o(e) {
|
|
48
|
+
switch (this.debugLog("handleNativePlayerStateChange", e), e) {
|
|
49
|
+
case "active":
|
|
50
|
+
this.playbackState = "PLAYING";
|
|
51
|
+
break;
|
|
52
|
+
case "idle":
|
|
53
|
+
case "seeking":
|
|
54
|
+
this.playbackState = "STALLED";
|
|
55
|
+
break;
|
|
56
|
+
case "paused":
|
|
57
|
+
case "ready":
|
|
58
|
+
this.playbackState = "NOT_PLAYING";
|
|
59
|
+
break;
|
|
60
|
+
case "stopped":
|
|
61
|
+
this.playbackState = "NOT_PLAYING";
|
|
62
|
+
break;
|
|
63
|
+
case "uninitialized":
|
|
64
|
+
this.playbackState = "IDLE";
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
this.debugLog("No handling for state", e);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async #s() {
|
|
72
|
+
this.debugLog("handleNetworkError");
|
|
73
|
+
let t = a.timestamp("streaming_metrics:playback_statistics:actualStartTimestamp");
|
|
74
|
+
if ((t === void 0 ? 0 : Math.abs(a.now() - t)) >= 36e5) {
|
|
75
|
+
let e = structuredClone(this.currentMediaProduct), t = this.currentTime;
|
|
76
|
+
this.finishCurrentMediaProduct("error"), e && (await this.hardReload(e, t), await this.play());
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
await Promise.race([this.mediaStateChange("idle"), new Promise((e) => {
|
|
80
|
+
window.addEventListener("online", () => e("online"));
|
|
81
|
+
})]) === "idle" && e.dispatchError(new n("PENetwork", "NPN01"));
|
|
82
|
+
}
|
|
83
|
+
abandon() {
|
|
84
|
+
g?.deviceMode === "exclusive" && this.#n.selectSystemDevice();
|
|
85
|
+
}
|
|
86
|
+
getPosition() {
|
|
87
|
+
return this.currentTime;
|
|
88
|
+
}
|
|
89
|
+
async handleAutomaticTransitionToPreloadedMediaProduct() {
|
|
90
|
+
await this.nativeEvent("mediaduration"), this.#r = void 0;
|
|
91
|
+
let n = t.getMediaProductTransition(this.preloadedStreamingSessionId);
|
|
92
|
+
if (!n) {
|
|
93
|
+
console.warn("No media product transition saved for next item. Stopping playback."), this.playbackState = "NOT_PLAYING";
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
let { mediaProduct: r, playbackContext: i } = n, a = {
|
|
97
|
+
...i,
|
|
98
|
+
actualDuration: this.#t
|
|
99
|
+
};
|
|
100
|
+
this.preloadedStreamingSessionId && t.saveMediaProductTransition(this.preloadedStreamingSessionId, {
|
|
101
|
+
mediaProduct: r,
|
|
102
|
+
playbackContext: a
|
|
103
|
+
}), await this.mediaStateChange("active"), e.dispatchEvent(l(r, a)), this.currentStreamingSessionId = this.preloadedStreamingSessionId, this.mediaProductStarted(this.currentStreamingSessionId);
|
|
104
|
+
}
|
|
105
|
+
async load(n, r) {
|
|
106
|
+
this.debugLog("load", n), this.currentTime = n.assetPosition, this.startAssetPosition = n.assetPosition, await this.reset();
|
|
107
|
+
let { assetPosition: i, mediaProduct: a, playbackInfo: o, streamInfo: s } = n, { securityToken: c, streamFormat: d, streamUrl: f } = s;
|
|
108
|
+
this.currentStreamingSessionId = s.streamingSessionId, r === "explicit" && (this.playbackState = "NOT_PLAYING");
|
|
109
|
+
let p = this.nativeEvent("mediaduration");
|
|
110
|
+
if (d) this.#n.load(f, d, c);
|
|
111
|
+
else throw Error("Stream format is undefined.");
|
|
112
|
+
if (await p, this.currentStreamingSessionId !== s.streamingSessionId) return;
|
|
113
|
+
this.debugLog("load() duration is", this.#t), i !== 0 && i < this.#t ? (async () => {
|
|
114
|
+
await this.mediaStateChange("active"), this.currentStreamingSessionId === s.streamingSessionId && (await this.seek(i), this.currentTime = i);
|
|
115
|
+
})().catch(console.error) : this.currentTime = 0;
|
|
116
|
+
let m = u({
|
|
117
|
+
assetPosition: i,
|
|
118
|
+
duration: this.#t,
|
|
119
|
+
playbackInfo: o,
|
|
120
|
+
streamInfo: s
|
|
121
|
+
});
|
|
122
|
+
t.saveMediaProductTransition(s.streamingSessionId, {
|
|
123
|
+
mediaProduct: a,
|
|
124
|
+
playbackContext: m
|
|
125
|
+
}), this.debugLog("load() mediaProductTransition"), e.dispatchEvent(l(a, m)), this.debugLog("load() pb NOT_PLAYING"), this.debugLog("load() done");
|
|
126
|
+
}
|
|
127
|
+
mediaStateChange(e) {
|
|
128
|
+
return new Promise((t) => {
|
|
129
|
+
let n = (r) => {
|
|
130
|
+
r.target === e && (this.#n.removeEventListener("mediastate", n), t(r.target));
|
|
131
|
+
};
|
|
132
|
+
this.#n.addEventListener("mediastate", n);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
nativeEvent(e) {
|
|
136
|
+
return new Promise((t) => {
|
|
137
|
+
let n = (r) => {
|
|
138
|
+
this.#n.removeEventListener(e, n), t(r);
|
|
139
|
+
};
|
|
140
|
+
this.#n.addEventListener(e, n);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async next(e) {
|
|
144
|
+
this.debugLog("next", e), this.hasNextItem() && await this.unloadPreloadedMediaProduct();
|
|
145
|
+
let { mediaProduct: n, playbackInfo: r, streamInfo: i } = e, { securityToken: a, streamFormat: o, streamUrl: s, streamingSessionId: c } = i;
|
|
146
|
+
this.preloadedStreamingSessionId = c, this.debugLog("preloading", s, "for", c), o ? (this.#n.preload(s, o, a), this.isActivePlayer || this.#n.pause()) : console.error("Stream format undefined for preload."), this.debugLog("preloading done");
|
|
147
|
+
let l = u({
|
|
148
|
+
assetPosition: 0,
|
|
149
|
+
duration: 0,
|
|
150
|
+
playbackInfo: r,
|
|
151
|
+
streamInfo: i
|
|
152
|
+
});
|
|
153
|
+
t.saveMediaProductTransition(c, {
|
|
154
|
+
mediaProduct: n,
|
|
155
|
+
playbackContext: l
|
|
156
|
+
}), this.#r = e;
|
|
157
|
+
}
|
|
158
|
+
pause() {
|
|
159
|
+
this.#n.pause();
|
|
160
|
+
}
|
|
161
|
+
async play() {
|
|
162
|
+
if (this.debugLog("play"), await this.maybeHardReload(), this.playbackState === "IDLE") {
|
|
163
|
+
this.debugLog("play()", this.playbackState, "returning early");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.setStateToXIfNotYInZMs(1e3, "PLAYING", "STALLED"), await this.updateOutputDevice(), this.mediaProductStarted(this.currentStreamingSessionId), this.debugLog("nativePlayer", "play()"), this.#n.play();
|
|
167
|
+
}
|
|
168
|
+
async playbackEngineEndedHandler(e) {
|
|
169
|
+
if (this.isActivePlayer) {
|
|
170
|
+
let { reason: t } = e.detail;
|
|
171
|
+
t === "completed" && (this.hasNextItem() ? await this.handleAutomaticTransitionToPreloadedMediaProduct() : (r.preloadedStreamingSessionId ? this.debugLog(`Switching player from ${this.name} to ${r.preloadPlayer?.name}`) : this.debugLog("No next item queued."), this.playbackState = "NOT_PLAYING"));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
get ready() {
|
|
175
|
+
return Promise.resolve();
|
|
176
|
+
}
|
|
177
|
+
registerEventListeners() {
|
|
178
|
+
this.debugLog("registerEventListeners"), this.#n.addEventListener("mediacurrenttime", (e) => {
|
|
179
|
+
this.currentTime = Number(e.target);
|
|
180
|
+
}), this.#n.addEventListener("mediastate", (e) => {
|
|
181
|
+
e.target === "completed" ? this.finishCurrentMediaProduct("completed") : this.#o(e.target);
|
|
182
|
+
}), this.#n.addEventListener("devices", (e) => {
|
|
183
|
+
g ? g.addNativeDevices(e.target) : console.error("Output devices not loaded.");
|
|
184
|
+
}), this.#n.addEventListener("devicedisconnected", () => {
|
|
185
|
+
e.dispatchEvent(p()), this.#i("devicedisconnected");
|
|
186
|
+
}), this.#n.addEventListener("deviceexclusivemodenotallowed", () => this.#i("deviceexclusivemodenotallowed")), this.#n.addEventListener("deviceformatnotsupported", () => this.#i("deviceformatnotsupported")), this.#n.addEventListener("devicelocked", () => this.#i("devicelocked")), this.#n.addEventListener("devicenotfound", () => this.#i("devicenotfound")), this.#n.addEventListener("deviceunknownerror", () => this.#i("deviceunknownerror")), this.#n.addEventListener("mediaduration", (e) => {
|
|
187
|
+
this.#t = Number(e.target);
|
|
188
|
+
}), this.#n.addEventListener("mediaerror", (e) => this.#a(e)), this.#n.addEventListener("mediamaxconnectionsreached", () => {
|
|
189
|
+
this.#s().catch(console.error);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async reset({ keepPreload: e } = { keepPreload: !1 }) {
|
|
193
|
+
this.currentStreamingSessionId !== void 0 && (this.debugLog("reset"), e || await this.unloadPreloadedMediaProduct(), this.#n.stop(), this.playbackState !== "IDLE" && this.finishCurrentMediaProduct("skip"), this.detachPlaybackEngineEndedHandler(), this.currentStreamingSessionId = void 0, e || (this.preloadedStreamingSessionId = void 0), this.playbackState = "IDLE");
|
|
194
|
+
}
|
|
195
|
+
async seek(e) {
|
|
196
|
+
this.hasStarted() || await this.mediaStateChange("active"), this.seekStart(this.currentTime), this.currentTime = e, this.#n.seek(e), this.seekEnd(this.currentTime);
|
|
197
|
+
}
|
|
198
|
+
async skipToPreloadedMediaProduct() {
|
|
199
|
+
this.debugLog("skipToPreloadedMediaProduct", this.preloadedStreamingSessionId);
|
|
200
|
+
let e = this.currentStreamingSessionId === void 0;
|
|
201
|
+
if (this.preloadedStreamingSessionId && this.#r) {
|
|
202
|
+
let n = t.getMediaProductTransition(this.preloadedStreamingSessionId);
|
|
203
|
+
n && (this.#r.mediaProduct = n.mediaProduct), await this.load(this.#r, "implicit"), await this.updateOutputDevice(), e && (this.playbackState = "PLAYING"), this.playbackState === "IDLE" && (this.playbackState = "NOT_PLAYING");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
console.warn("No preloaded item in native player.");
|
|
207
|
+
}
|
|
208
|
+
async unloadPreloadedMediaProduct() {
|
|
209
|
+
this.debugLog("unloadPreloadedMediaProduct", this.preloadedStreamingSessionId), this.hasNextItem() && (this.cleanUpStoredPreloadInfo(), "cancelPreload" in this.#n ? this.#n.cancelPreload() : console.warn("cancelPreload not available. Update native player."));
|
|
210
|
+
}
|
|
211
|
+
updateDeviceMode() {
|
|
212
|
+
this.updateOutputDevice()?.catch(console.error), g && e.dispatchEvent(s(g.deviceMode));
|
|
213
|
+
}
|
|
214
|
+
updateOutputDevice() {
|
|
215
|
+
if (!g || (this.debugLog("updateOutputDevice", g.activeDevice), !g.activeDevice)) return Promise.resolve();
|
|
216
|
+
let { nativeDeviceId: t } = g.activeDevice;
|
|
217
|
+
if (this.outputDeviceType = g.activeDevice.type, t === "default") this.#e !== "default" && (this.#n.selectSystemDevice(), e.dispatchEvent(c("default")), this.#e = "default");
|
|
218
|
+
else if (t) {
|
|
219
|
+
let n = g.getNativeDevice(t);
|
|
220
|
+
n && (this.#n.selectDevice(n, g.deviceMode), e.dispatchEvent(c(g.activeDevice.id)), e.dispatchEvent(s(g.deviceMode)), this.#e = t);
|
|
221
|
+
} else throw Error(`Device with sinkId ${t} not found.`);
|
|
222
|
+
return Promise.resolve();
|
|
223
|
+
}
|
|
224
|
+
get volume() {
|
|
225
|
+
return i("desiredVolumeLevel");
|
|
226
|
+
}
|
|
227
|
+
set volume(e) {
|
|
228
|
+
this.debugLog("Setting volume to", e), this.#n.setVolume(e * 100);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
//#endregion
|
|
232
|
+
export { _ as default };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { a as e, t } from "./state-BT7sE_jc-iVaBwnBC.js";
|
|
2
|
+
import { i as n, n as r, r as i, t as a } from "./generate-guid-BMGZjV-R-D16yCCHx.js";
|
|
3
|
+
//#region ../player/dist/output-devices-CPJfYcO-.js
|
|
4
|
+
var o = /* @__PURE__ */ i(((e, t) => {
|
|
5
|
+
t.exports = (function() {
|
|
6
|
+
function e(e, t, n, r, i) {
|
|
7
|
+
return e < t || n < t ? e > n ? n + 1 : e + 1 : r === i ? t : t + 1;
|
|
8
|
+
}
|
|
9
|
+
return function(t, n) {
|
|
10
|
+
if (t === n) return 0;
|
|
11
|
+
if (t.length > n.length) {
|
|
12
|
+
var r = t;
|
|
13
|
+
t = n, n = r;
|
|
14
|
+
}
|
|
15
|
+
for (var i = t.length, a = n.length; i > 0 && t.charCodeAt(i - 1) === n.charCodeAt(a - 1);) i--, a--;
|
|
16
|
+
for (var o = 0; o < i && t.charCodeAt(o) === n.charCodeAt(o);) o++;
|
|
17
|
+
if (i -= o, a -= o, i === 0 || a < 3) return a;
|
|
18
|
+
var s = 0, c, l, u, d, f, p, m, h, g, _, v, y, b = [];
|
|
19
|
+
for (c = 0; c < i; c++) b.push(c + 1), b.push(t.charCodeAt(o + c));
|
|
20
|
+
for (var x = b.length - 1; s < a - 3;) for (g = n.charCodeAt(o + (l = s)), _ = n.charCodeAt(o + (u = s + 1)), v = n.charCodeAt(o + (d = s + 2)), y = n.charCodeAt(o + (f = s + 3)), p = s += 4, c = 0; c < x; c += 2) m = b[c], h = b[c + 1], l = e(m, l, u, g, h), u = e(l, u, d, _, h), d = e(u, d, f, v, h), p = e(d, f, p, y, h), b[c] = p, f = d, d = u, u = l, l = m;
|
|
21
|
+
for (; s < a;) for (g = n.charCodeAt(o + (l = s)), p = ++s, c = 0; c < x; c += 2) m = b[c], b[c] = p = e(m, l, p, g, b[c + 1]), l = m;
|
|
22
|
+
return p;
|
|
23
|
+
};
|
|
24
|
+
})();
|
|
25
|
+
})), s = /* @__PURE__ */ a(r(), 1), c = /* @__PURE__ */ a(o(), 1);
|
|
26
|
+
function l(e) {
|
|
27
|
+
return new CustomEvent("device-change", { detail: { devices: e } });
|
|
28
|
+
}
|
|
29
|
+
var u = s.default.parse(navigator.userAgent), d = class {
|
|
30
|
+
controllableVolume;
|
|
31
|
+
id;
|
|
32
|
+
name;
|
|
33
|
+
nativeDeviceId;
|
|
34
|
+
type;
|
|
35
|
+
webDeviceId;
|
|
36
|
+
constructor({ controllableVolume: e, name: t, nativeDeviceId: r, type: i, webDeviceId: a }) {
|
|
37
|
+
this.name = t, this.id = r === "default" && a === "default" ? "default" : n(), this.nativeDeviceId = r, this.webDeviceId = a, this.type = i, this.controllableVolume = e !== !1;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function f(e) {
|
|
41
|
+
if (m(e)) return "windowsCommunication";
|
|
42
|
+
if ("id" in e && e.id === "BuiltInSpeakerDevice") return "builtIn";
|
|
43
|
+
if ("type" in e && e.type === "airplay") return "airplay";
|
|
44
|
+
if ("label" in e) {
|
|
45
|
+
let t = e.label.toLowerCase();
|
|
46
|
+
if (t.includes("bluetooth")) return "bluetooth";
|
|
47
|
+
if (t.includes("displayport")) return "displayPort";
|
|
48
|
+
if (t.includes("hdmi")) return "hdmi";
|
|
49
|
+
if (t.includes("usb")) return "usb";
|
|
50
|
+
if (t.includes("built-in")) return "builtIn";
|
|
51
|
+
if (t.includes("airplay")) return "airplay";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function p(e, t) {
|
|
55
|
+
let n = t.toLowerCase(), r = e;
|
|
56
|
+
return n.includes("mac") && (r = (e.split("(")[0] ?? "").trim()), r;
|
|
57
|
+
}
|
|
58
|
+
function m(e) {
|
|
59
|
+
let t;
|
|
60
|
+
return "label" in e && (t = e.label), "name" in e && (t = e.name), t?.startsWith("Communications") ?? !1;
|
|
61
|
+
}
|
|
62
|
+
function h(e, t) {
|
|
63
|
+
if (t = p(t, u.os.name || ""), [...e].length === 0 || t === "") return;
|
|
64
|
+
let n = [...e].find((e) => e.name === t);
|
|
65
|
+
if (n) return n;
|
|
66
|
+
let r = [...e].filter((e) => t.includes(e.name) || e.name.includes(t)).map((e) => ({
|
|
67
|
+
device: e,
|
|
68
|
+
distance: (0, c.default)(e.name, t)
|
|
69
|
+
})).sort((e, t) => e.distance - t.distance).reverse();
|
|
70
|
+
if (r.length > 0) {
|
|
71
|
+
let e = r.pop();
|
|
72
|
+
if (e && e.distance <= 16) return e.device;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
var g = new class {
|
|
76
|
+
#e;
|
|
77
|
+
#t;
|
|
78
|
+
#n = "shared";
|
|
79
|
+
#r;
|
|
80
|
+
#i;
|
|
81
|
+
#a;
|
|
82
|
+
outputDevices;
|
|
83
|
+
constructor() {
|
|
84
|
+
this.#i = /* @__PURE__ */ new Set(), this.#a = /* @__PURE__ */ new Set(), this.#r = new EventTarget(), this.#t = new d({
|
|
85
|
+
name: "System Default",
|
|
86
|
+
nativeDeviceId: "default",
|
|
87
|
+
type: "systemDefault",
|
|
88
|
+
webDeviceId: "default"
|
|
89
|
+
}), this.#e = this.#t, this.outputDevices = new Set([this.#t]), this.hydrateWebDevices().then().catch(console.error), navigator.mediaDevices.addEventListener("devicechange", () => {
|
|
90
|
+
this.hydrateWebDevices().then().catch(console.error);
|
|
91
|
+
}), this.#r.addEventListener("native-devices", ((e) => {
|
|
92
|
+
this.#i = new Set(e.detail), this.queueUpdate().then().catch(console.error);
|
|
93
|
+
})), this.#r.addEventListener("web-devices", ((e) => {
|
|
94
|
+
this.#a = new Set(e.detail), this.queueUpdate().then().catch(console.error);
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
set activeDevice(e) {
|
|
98
|
+
this.#e = e, this.#n = "shared", t.activePlayer?.updateOutputDevice()?.catch(console.error);
|
|
99
|
+
}
|
|
100
|
+
get activeDevice() {
|
|
101
|
+
return this.#e;
|
|
102
|
+
}
|
|
103
|
+
addNativeDevices(e) {
|
|
104
|
+
this.#r.dispatchEvent(new CustomEvent("native-devices", { detail: e }));
|
|
105
|
+
}
|
|
106
|
+
addWebDevices(e) {
|
|
107
|
+
e = e.filter((e) => e.deviceId !== "default"), this.#r.dispatchEvent(new CustomEvent("web-devices", { detail: e }));
|
|
108
|
+
}
|
|
109
|
+
set deviceMode(e) {
|
|
110
|
+
let { activeDevice: n } = this, { activePlayer: r } = t;
|
|
111
|
+
n && r?.name === "nativePlayer" && this.deviceMode !== e && (this.#n = e, r.updateDeviceMode());
|
|
112
|
+
}
|
|
113
|
+
get deviceMode() {
|
|
114
|
+
return this.#n;
|
|
115
|
+
}
|
|
116
|
+
emitDeviceChange() {
|
|
117
|
+
e.dispatchEvent(l([...this.outputDevices]));
|
|
118
|
+
}
|
|
119
|
+
getNativeDevice(e) {
|
|
120
|
+
return [...this.#i].find((t) => t.id === e);
|
|
121
|
+
}
|
|
122
|
+
async hydrateWebDevices() {
|
|
123
|
+
let e = (await navigator.mediaDevices.enumerateDevices()).filter((e) => e.kind === "audiooutput");
|
|
124
|
+
this.addWebDevices(e);
|
|
125
|
+
}
|
|
126
|
+
mergeDevices() {
|
|
127
|
+
[...this.outputDevices].filter((e) => e.id !== "default").forEach((e) => {
|
|
128
|
+
e.nativeDeviceId = void 0, e.webDeviceId = void 0;
|
|
129
|
+
}), this.#i.forEach((e) => {
|
|
130
|
+
let t = h(this.outputDevices, e.name);
|
|
131
|
+
t ? (t.nativeDeviceId = e.id, t.controllableVolume = e.controllableVolume, t.type = f(e) || t.type) : this.outputDevices.add(new d({
|
|
132
|
+
controllableVolume: e.controllableVolume,
|
|
133
|
+
name: p(e.name, u.os.name || ""),
|
|
134
|
+
nativeDeviceId: e.id,
|
|
135
|
+
type: f(e)
|
|
136
|
+
}));
|
|
137
|
+
}), this.#a.forEach((e) => {
|
|
138
|
+
let t = h(this.outputDevices, e.label);
|
|
139
|
+
t ? (t.webDeviceId = e.deviceId, t.type = f(e) || t.type) : this.outputDevices.add(new d({
|
|
140
|
+
name: p(e.label, u.os.name || ""),
|
|
141
|
+
type: f(e),
|
|
142
|
+
webDeviceId: e.deviceId
|
|
143
|
+
}));
|
|
144
|
+
}), [...this.outputDevices].filter((e) => e.webDeviceId === void 0 && e.nativeDeviceId === void 0 || e.type === "airplay" || e.type === "windowsCommunication").forEach((e) => this.outputDevices.delete(e));
|
|
145
|
+
}
|
|
146
|
+
async queueUpdate() {
|
|
147
|
+
let e = new Promise((e) => this.#r.addEventListener("native-devices", ((t) => e(t.detail)), { once: !0 })), t = new Promise((e) => this.#r.addEventListener("web-devices", ((t) => e(t.detail)), { once: !0 }));
|
|
148
|
+
await Promise.any([
|
|
149
|
+
e,
|
|
150
|
+
t,
|
|
151
|
+
((e) => new Promise((t) => setTimeout(() => t(), e)))(1e3)
|
|
152
|
+
]), this.mergeDevices(), this.emitDeviceChange();
|
|
153
|
+
}
|
|
154
|
+
}();
|
|
155
|
+
//#endregion
|
|
156
|
+
export { g as outputDevices };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { a as e, c as t, s as n, t as r, u as i } from "./state-BT7sE_jc-iVaBwnBC.js";
|
|
2
|
+
//#region ../player/dist/pushkin-C7W2HCqN.js
|
|
3
|
+
var a = new class {
|
|
4
|
+
#e;
|
|
5
|
+
#t = !1;
|
|
6
|
+
#n;
|
|
7
|
+
#r;
|
|
8
|
+
constructor(e) {
|
|
9
|
+
this.#r = new URL(e), this.synchronize();
|
|
10
|
+
}
|
|
11
|
+
now(e = Date.now()) {
|
|
12
|
+
return !this.#n || !this.#e ? (console.warn("TrueTime is not yet synchronized"), e) : this.#n + (e - this.#e);
|
|
13
|
+
}
|
|
14
|
+
async synchronize() {
|
|
15
|
+
if (!(this.#e && Math.abs(Date.now() - this.#e) < 36e5 || this.#t)) {
|
|
16
|
+
this.#t = !0;
|
|
17
|
+
try {
|
|
18
|
+
let e = await fetch(this.#r);
|
|
19
|
+
e.ok && e.headers.has("date") && (this.#n = new Date(e.headers.get("date")).getTime(), this.#e = Date.now());
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error(e);
|
|
22
|
+
}
|
|
23
|
+
this.#t = !1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
timestamp(e, t) {
|
|
27
|
+
let n;
|
|
28
|
+
if (t) {
|
|
29
|
+
if (n = performance.getEntriesByName(e).find((e) => "detail" in e && e.detail === t), !n) throw ReferenceError(`There is no performance entry named "${e}" with detail "${t}"`);
|
|
30
|
+
} else n = performance.getEntriesByName(e).pop();
|
|
31
|
+
return n ? n.startTime : void 0;
|
|
32
|
+
}
|
|
33
|
+
}("https://api.tidal.com/v1/ping"), o = "streaming-privileges-revoked";
|
|
34
|
+
function s(e) {
|
|
35
|
+
return new CustomEvent(o, { detail: e });
|
|
36
|
+
}
|
|
37
|
+
var c;
|
|
38
|
+
async function l(e) {
|
|
39
|
+
let t = i("legacyApiUrl"), { url: n } = await (await fetch(t + "/rt/connect", {
|
|
40
|
+
headers: new Headers({
|
|
41
|
+
Authorization: "Bearer " + e,
|
|
42
|
+
"Content-Type": "application/json"
|
|
43
|
+
}),
|
|
44
|
+
method: "POST"
|
|
45
|
+
})).json();
|
|
46
|
+
return n;
|
|
47
|
+
}
|
|
48
|
+
function u(e) {
|
|
49
|
+
return new Promise((t) => {
|
|
50
|
+
e.addEventListener("open", () => t(), { once: !0 });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
var d = class i {
|
|
54
|
+
#e;
|
|
55
|
+
#t;
|
|
56
|
+
#n;
|
|
57
|
+
#r;
|
|
58
|
+
constructor() {
|
|
59
|
+
this.#r = void 0, this.#t = this.#i(), e.addEventListener("user-action", () => {
|
|
60
|
+
this.connected && this.userAction().then().catch(console.error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
static async ensure() {
|
|
64
|
+
await n() && (c ? c.connected || await c.reconnect() : c = new i());
|
|
65
|
+
}
|
|
66
|
+
static async refresh() {
|
|
67
|
+
if (!await n()) return;
|
|
68
|
+
let e = await t();
|
|
69
|
+
c && e && c.reconnect().catch(console.error);
|
|
70
|
+
}
|
|
71
|
+
async #i() {
|
|
72
|
+
let e = await t();
|
|
73
|
+
if (!e) throw Error("No access token to connect to Pushkin.");
|
|
74
|
+
let n = await l(e);
|
|
75
|
+
n && (this.#r = new WebSocket(n), await u(this.#r), this.#n = ((e) => this.#s(e.data)), this.#e = () => this.#o(), this.#r.addEventListener("message", this.#n, !1), this.#r.addEventListener("closed", this.#e, !1), window.addEventListener("online", () => this.#o(), { once: !0 }));
|
|
76
|
+
}
|
|
77
|
+
async #a(e) {
|
|
78
|
+
if (!this.#r) throw Error("No socket connected. Did you forget to call connect method in Pushkin service first?");
|
|
79
|
+
this.#r.readyState !== WebSocket.OPEN && await this.#t, this.#r.send(JSON.stringify(e));
|
|
80
|
+
}
|
|
81
|
+
#o() {
|
|
82
|
+
this.#t = this.#i();
|
|
83
|
+
}
|
|
84
|
+
#s(t) {
|
|
85
|
+
let n = JSON.parse(t);
|
|
86
|
+
switch (n.type) {
|
|
87
|
+
case "PRIVILEGED_SESSION_NOTIFICATION":
|
|
88
|
+
e.dispatchEvent(s(String(n.payload.clientDisplayName))), r.activePlayer?.pause();
|
|
89
|
+
break;
|
|
90
|
+
case "RECONNECT":
|
|
91
|
+
this.reconnect().catch(console.error);
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
console.warn("Unhandled event from Pushkin: ", n);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
get connected() {
|
|
99
|
+
return this.#r && this.#r.readyState === WebSocket.OPEN;
|
|
100
|
+
}
|
|
101
|
+
reconnect() {
|
|
102
|
+
return this.#r ? (this.#n && this.#r.removeEventListener("message", this.#n), this.#e && this.#r.removeEventListener("closed", this.#e), this.#r.close(), this.#t = this.#i(), this.#t) : Promise.resolve();
|
|
103
|
+
}
|
|
104
|
+
async userAction() {
|
|
105
|
+
this.connected || await this.reconnect();
|
|
106
|
+
try {
|
|
107
|
+
await this.#a({
|
|
108
|
+
payload: { startedAt: a.now() },
|
|
109
|
+
type: "USER_ACTION"
|
|
110
|
+
});
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error(e);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
//#endregion
|
|
117
|
+
export { d as n, a as t };
|