@christianriedl/media 1.0.2 → 1.0.5
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/playerService.d.ts +12 -3
- package/dist/playerService.js +23 -6
- package/dist/playerService.js.map +1 -1
- package/package.json +1 -1
- package/src/views/MusicPage.vue +106 -54
package/dist/playerService.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IRest } from '@christianriedl/rest';
|
|
2
2
|
import { ILogger, Dictionary } from '@christianriedl/utils';
|
|
3
|
+
import { EMediaType } from "./iMedia";
|
|
3
4
|
export declare enum EPlayState {
|
|
4
5
|
PowerOff = 0,
|
|
5
6
|
NoMedia = 1,
|
|
@@ -26,6 +27,11 @@ export interface IPlayerRequest {
|
|
|
26
27
|
trackNo?: number;
|
|
27
28
|
withStreamTitle?: boolean;
|
|
28
29
|
}
|
|
30
|
+
export interface IPlayerCommand {
|
|
31
|
+
playerName: string;
|
|
32
|
+
cmd: string;
|
|
33
|
+
value: string;
|
|
34
|
+
}
|
|
29
35
|
export declare class PlayerService {
|
|
30
36
|
rest: IRest;
|
|
31
37
|
mediaUrl: string;
|
|
@@ -33,9 +39,12 @@ export declare class PlayerService {
|
|
|
33
39
|
playerNames: string[];
|
|
34
40
|
playerStates: Dictionary<IPlayerState>;
|
|
35
41
|
constructor(rest: IRest, log: ILogger);
|
|
36
|
-
getPlayers(): Promise<string[]>;
|
|
42
|
+
getPlayers(mediaType?: EMediaType, isReady?: boolean): Promise<string[]>;
|
|
37
43
|
getPlayerState(playerName: string): Promise<IPlayerState | null>;
|
|
38
44
|
play(playerRequest: IPlayerRequest): Promise<boolean>;
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
stop(playerName: string): Promise<boolean>;
|
|
46
|
+
pause(playerName: string): Promise<boolean>;
|
|
47
|
+
next(playerName: string): Promise<boolean>;
|
|
48
|
+
previous(playerName: string): Promise<boolean>;
|
|
49
|
+
command(playerCommand: IPlayerCommand): Promise<boolean>;
|
|
41
50
|
}
|
package/dist/playerService.js
CHANGED
|
@@ -19,8 +19,13 @@ export class PlayerService {
|
|
|
19
19
|
this.rest = rest;
|
|
20
20
|
this.mediaUrl = rest.serviceUrl;
|
|
21
21
|
}
|
|
22
|
-
async getPlayers() {
|
|
23
|
-
const
|
|
22
|
+
async getPlayers(mediaType, isReady) {
|
|
23
|
+
const query = {};
|
|
24
|
+
if (mediaType)
|
|
25
|
+
query.mediaType = mediaType;
|
|
26
|
+
if (isReady)
|
|
27
|
+
query.isReady = isReady;
|
|
28
|
+
const players = await this.rest.getData('apiplayer/players', query);
|
|
24
29
|
this.playerNames = players.result;
|
|
25
30
|
return this.playerNames;
|
|
26
31
|
}
|
|
@@ -37,12 +42,24 @@ export class PlayerService {
|
|
|
37
42
|
const result = await this.rest.postData('apiplayer/play', playerRequest);
|
|
38
43
|
return result.ok;
|
|
39
44
|
}
|
|
40
|
-
async
|
|
41
|
-
const result = await this.rest.postData('apiplayer/playstop'
|
|
45
|
+
async stop(playerName) {
|
|
46
|
+
const result = await this.rest.postData('apiplayer/playstop/' + playerName);
|
|
42
47
|
return result.ok;
|
|
43
48
|
}
|
|
44
|
-
async
|
|
45
|
-
const result = await this.rest.postData('apiplayer/playpause'
|
|
49
|
+
async pause(playerName) {
|
|
50
|
+
const result = await this.rest.postData('apiplayer/playpause/' + playerName);
|
|
51
|
+
return result.ok;
|
|
52
|
+
}
|
|
53
|
+
async next(playerName) {
|
|
54
|
+
const result = await this.rest.postData('apiplayer/playnext/' + playerName);
|
|
55
|
+
return result.ok;
|
|
56
|
+
}
|
|
57
|
+
async previous(playerName) {
|
|
58
|
+
const result = await this.rest.postData('apiplayer/playprevious/' + playerName);
|
|
59
|
+
return result.ok;
|
|
60
|
+
}
|
|
61
|
+
async command(playerCommand) {
|
|
62
|
+
const result = await this.rest.postData('apiplayer/playcommand', playerCommand);
|
|
46
63
|
return result.ok;
|
|
47
64
|
}
|
|
48
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playerService.js","sourceRoot":"","sources":["../src/playerService.ts"],"names":[],"mappings":"AAOA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IAClB,mDAAY,CAAA;IACZ,iDAAO,CAAA;IACP,+CAAM,CAAA;IACN,iDAAO,CAAA;IACP,2CAAI,CAAA;IACJ,iDAAO,CAAA;IACP,mDAAQ,CAAA;AACZ,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB;
|
|
1
|
+
{"version":3,"file":"playerService.js","sourceRoot":"","sources":["../src/playerService.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/views/MusicPage.vue
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
const volume = ref(0);
|
|
27
27
|
const mute = ref(false);
|
|
28
28
|
|
|
29
|
-
const isLocal = computed(() => currentPlayer == 'Local');
|
|
29
|
+
const isLocal = computed(() => currentPlayer.value == 'Local');
|
|
30
30
|
const backVisible = computed(() => selected.value.ItemType != EItemType.AudioRoot);
|
|
31
31
|
const downloadAlbumVisible = computed(() => selected.value.ItemType == EItemType.AudioAlbum && !playingTrackUrl.value && !isMobile);
|
|
32
32
|
const downloadVisible = computed(() => playingTrackUrl.value && !isMobile);
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
}
|
|
43
43
|
return '';
|
|
44
44
|
});
|
|
45
|
-
let
|
|
45
|
+
let syncTimer = 0;
|
|
46
|
+
let cmdTimer = 0;
|
|
47
|
+
let syncRemote = false;
|
|
46
48
|
|
|
47
49
|
window.addEventListener('popstate', onPopState);
|
|
48
50
|
function onPopState (event: any) {
|
|
@@ -68,7 +70,7 @@
|
|
|
68
70
|
selected.value = root;
|
|
69
71
|
items.splice(0, items.length, ...root.Folders);
|
|
70
72
|
computeListHeight();
|
|
71
|
-
const players = await playerService.getPlayers();
|
|
73
|
+
const players = await playerService.getPlayers(EMediaType.Audio, true);
|
|
72
74
|
playerNames.splice(playerNames.length, 0, ...players);
|
|
73
75
|
})
|
|
74
76
|
watch(appState.bodyHeight, () => computeListHeight());
|
|
@@ -108,51 +110,61 @@
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
function listBack() {
|
|
113
|
+
syncRemote = false;
|
|
114
|
+
playingTrack.value = null;
|
|
111
115
|
const parent = mediaService.folders[selected.value.DLNAParentID];
|
|
112
116
|
selected.value = parent;
|
|
113
117
|
items.splice(0, items.length, ...parent.Folders);
|
|
114
118
|
computeListHeight();
|
|
115
119
|
}
|
|
116
120
|
function onTimeUpdate() {
|
|
117
|
-
|
|
121
|
+
setPosition(audio.value!.currentTime);
|
|
122
|
+
}
|
|
123
|
+
function setPosition(value: number) {
|
|
124
|
+
position.value = value;
|
|
118
125
|
if (playingTrack.value && playingTrack.value.Duration > 0)
|
|
119
126
|
positionLength.value = position.value * 100 / playingTrack.value.Duration;
|
|
120
127
|
else
|
|
121
128
|
positionLength.value = 0;
|
|
122
129
|
}
|
|
123
130
|
function onPlayerChange() {
|
|
124
|
-
if (
|
|
125
|
-
window.clearTimeout(
|
|
126
|
-
|
|
131
|
+
if (syncTimer) {
|
|
132
|
+
window.clearTimeout(syncTimer);
|
|
133
|
+
syncTimer = 0;
|
|
127
134
|
}
|
|
128
|
-
if (
|
|
129
|
-
|
|
135
|
+
if (!isLocal.value) {
|
|
136
|
+
syncTimer = window.setTimeout(() => getPlayerState(), 1000);
|
|
137
|
+
syncRemote = true;
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
async function getPlayerState() {
|
|
133
|
-
|
|
141
|
+
syncTimer = 0;
|
|
142
|
+
const playerState = await playerService.getPlayerState(currentPlayer.value);
|
|
134
143
|
playerState.state = Helper.stringToEnum(EPlayState, playerState.state);
|
|
135
|
-
paused.value = playerState.state == EPlayState.Paused;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
position.value = playingTrack.value.duration * playerState.duration / 100;
|
|
150
|
-
}
|
|
144
|
+
paused.value = playerState.state == EPlayState.Paused || playerState.state == EPlayState.Stopped;
|
|
145
|
+
if (!cmdTimer) {
|
|
146
|
+
volume.value = playerState.volume;
|
|
147
|
+
mute.value = playerState.mute;
|
|
148
|
+
}
|
|
149
|
+
if (syncRemote) {
|
|
150
|
+
if (!selected.value || playerState.albumId != selected.value.DLNAID) {
|
|
151
|
+
const album = mediaService.folders[playerState.albumId];
|
|
152
|
+
if (album) {
|
|
153
|
+
const audios = await mediaService.getAudios(album);
|
|
154
|
+
selected.value = audios;
|
|
155
|
+
items.splice(0, items.length, ...audios.Files);
|
|
156
|
+
playItems.splice(0, items.length, ...audios.Files);
|
|
157
|
+
computeListHeight();
|
|
151
158
|
}
|
|
152
|
-
|
|
159
|
+
}
|
|
160
|
+
if (playerState.mediaId) {
|
|
161
|
+
playIndex.value = items.findIndex((it) => it.DLNAID == playerState.mediaId);
|
|
162
|
+
if (playIndex.value >= 0)
|
|
163
|
+
playingTrack.value = items[playIndex.value];
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
|
-
|
|
166
|
+
setPosition(playerState.duration);
|
|
167
|
+
syncTimer = window.setTimeout(() => getPlayerState(), 1000);
|
|
156
168
|
}
|
|
157
169
|
function onEnded() {
|
|
158
170
|
mediaService.log.trace(`onEnded ${playIndex} ended`);
|
|
@@ -167,7 +179,7 @@
|
|
|
167
179
|
paused.value = false;
|
|
168
180
|
playingTrack.value = item;
|
|
169
181
|
playingTrackUrl.value = mediaService.getAudioUrl(item);
|
|
170
|
-
if (isLocal) {
|
|
182
|
+
if (isLocal.value) {
|
|
171
183
|
audio.value!.src = playingTrackUrl.value;
|
|
172
184
|
audio.value!.load();
|
|
173
185
|
audio.value!.play()
|
|
@@ -175,15 +187,23 @@
|
|
|
175
187
|
}
|
|
176
188
|
else {
|
|
177
189
|
const rc = await playerService.play({
|
|
178
|
-
playerName: currentPlayer,
|
|
190
|
+
playerName: currentPlayer.value,
|
|
179
191
|
folderId: selected.value.DLNAID,
|
|
180
192
|
mediaId: playingTrack.value.DLNAID,
|
|
181
193
|
trackNo: playingTrack.value.TrackNo
|
|
182
194
|
});
|
|
183
195
|
}
|
|
184
196
|
}
|
|
197
|
+
async function playFolder() {
|
|
198
|
+
const rc = await playerService.play({
|
|
199
|
+
playerName: currentPlayer.value,
|
|
200
|
+
folderId: selected.value.DLNAID,
|
|
201
|
+
trackNo: -1
|
|
202
|
+
});
|
|
203
|
+
syncRemote = true;
|
|
204
|
+
}
|
|
185
205
|
function playpause() {
|
|
186
|
-
if (isLocal) {
|
|
206
|
+
if (isLocal.value) {
|
|
187
207
|
if (audio.value!.paused) {
|
|
188
208
|
paused.value = false;
|
|
189
209
|
audio.value!.play()
|
|
@@ -194,20 +214,32 @@
|
|
|
194
214
|
audio.value!.pause();
|
|
195
215
|
}
|
|
196
216
|
}
|
|
197
|
-
if (paused.value) {
|
|
198
|
-
playerService.play({ playerName: currentPlayer });
|
|
199
|
-
}
|
|
200
217
|
else {
|
|
201
|
-
|
|
218
|
+
if (paused.value) {
|
|
219
|
+
playerService.play({ playerName: currentPlayer.value });
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
playerService.pause(currentPlayer.value);
|
|
223
|
+
}
|
|
202
224
|
}
|
|
203
225
|
}
|
|
204
226
|
function previous() {
|
|
205
|
-
if (
|
|
206
|
-
|
|
227
|
+
if (isLocal.value) {
|
|
228
|
+
if (playIndex.value > 0)
|
|
229
|
+
play(playIndex.value - 1);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
playerService.previous(currentPlayer.value);
|
|
233
|
+
}
|
|
207
234
|
}
|
|
208
235
|
function next() {
|
|
209
|
-
if (
|
|
210
|
-
|
|
236
|
+
if (isLocal.value) {
|
|
237
|
+
if (playIndex.value < playItems.length - 1)
|
|
238
|
+
play(playIndex.value + 1);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
playerService.next(currentPlayer.value);
|
|
242
|
+
}
|
|
211
243
|
}
|
|
212
244
|
function download() {
|
|
213
245
|
window.open(playingTrackUrl.value);
|
|
@@ -216,6 +248,19 @@
|
|
|
216
248
|
const downloadUrl = mediaService.getAlbumDownloadUrl(selected.value.Url);
|
|
217
249
|
window.open(downloadUrl);
|
|
218
250
|
}
|
|
251
|
+
function changeVolume() {
|
|
252
|
+
if (cmdTimer)
|
|
253
|
+
window.clearTimeout(cmdTimer);
|
|
254
|
+
|
|
255
|
+
cmdTimer = window.setTimeout(async () => {
|
|
256
|
+
await playerService.command({
|
|
257
|
+
playerName: currentPlayer.value,
|
|
258
|
+
cmd: "Volume",
|
|
259
|
+
value: volume.value.toString()
|
|
260
|
+
});
|
|
261
|
+
cmdTimer = 0;
|
|
262
|
+
}, 500);
|
|
263
|
+
}
|
|
219
264
|
function to_time(s: number): string {
|
|
220
265
|
var r = "";
|
|
221
266
|
s = Math.floor(s);
|
|
@@ -245,26 +290,26 @@
|
|
|
245
290
|
</audio>
|
|
246
291
|
<v-list-item three-line>
|
|
247
292
|
<v-row>
|
|
248
|
-
<v-col cols="
|
|
249
|
-
<v-select v-model="currentPlayer"
|
|
250
|
-
:items="playerNames"
|
|
251
|
-
persistent-hint
|
|
252
|
-
@update:modelValue="onPlayerChange"
|
|
253
|
-
dense solo hide-details single-line>
|
|
254
|
-
</v-select>
|
|
255
|
-
</v-col>
|
|
256
|
-
<v-col cols="2">
|
|
293
|
+
<v-col cols="1">
|
|
257
294
|
<v-list-item-avatar tile rounded="0" size="x-large" v-if="selected.ThumbnailUrl">
|
|
258
|
-
<img width="
|
|
295
|
+
<img width="60" :src="selected.ThumbnailUrl">
|
|
259
296
|
</v-list-item-avatar>
|
|
260
297
|
</v-col>
|
|
261
|
-
<v-col cols="
|
|
298
|
+
<v-col cols="7">
|
|
262
299
|
<v-list-item-content>
|
|
263
300
|
<v-list-item-title>{{selected.title}}</v-list-item-title>
|
|
264
301
|
<v-list-item-subtitle>{{selected.subTitle}}</v-list-item-subtitle>
|
|
265
302
|
<v-list-item-subtitle v-if="playingTrack">{{playingTrack.Name}}</v-list-item-subtitle>
|
|
266
303
|
</v-list-item-content>
|
|
267
304
|
</v-col>
|
|
305
|
+
<v-col cols="4">
|
|
306
|
+
<v-select v-model="currentPlayer"
|
|
307
|
+
:items="playerNames"
|
|
308
|
+
persistent-hint
|
|
309
|
+
@update:modelValue="onPlayerChange"
|
|
310
|
+
dense solo hide-details single-line>
|
|
311
|
+
</v-select>
|
|
312
|
+
</v-col>
|
|
268
313
|
</v-row>
|
|
269
314
|
</v-list-item>
|
|
270
315
|
<v-card-actions>
|
|
@@ -275,20 +320,27 @@
|
|
|
275
320
|
Album
|
|
276
321
|
<v-icon>{{$vuetify.icons.values.download}}</v-icon>
|
|
277
322
|
</v-btn>
|
|
278
|
-
<v-btn
|
|
323
|
+
<v-btn v-if="!isLocal" @click="playFolder">
|
|
324
|
+
{{selected.title}}
|
|
325
|
+
<v-icon>{{$vuetify.icons.values.play}}</v-icon>
|
|
326
|
+
</v-btn>
|
|
327
|
+
<v-btn small v-if="playingTrack" @click="playpause">
|
|
279
328
|
<v-icon>{{paused ? $vuetify.icons.values.play : $vuetify.icons.values.pause }}</v-icon>
|
|
280
329
|
</v-btn>
|
|
281
|
-
<v-btn small v-if="
|
|
330
|
+
<v-btn small v-if="playingTrack" @click="previous">
|
|
282
331
|
<v-icon>{{$vuetify.icons.values.prev}}</v-icon>
|
|
283
332
|
</v-btn>
|
|
284
|
-
<v-btn small v-if="
|
|
333
|
+
<v-btn small v-if="playingTrack" @click="next">
|
|
285
334
|
<v-icon>{{$vuetify.icons.values.next}}</v-icon>
|
|
286
335
|
</v-btn>
|
|
287
336
|
<v-btn small v-if="downloadVisible" @click="download">
|
|
288
337
|
<v-icon>{{$vuetify.icons.values.download}}</v-icon>
|
|
289
338
|
</v-btn>
|
|
339
|
+
<v-slider v-if="playingTrack" style="width:30%" color="red" track-color="blue" track-fill-color="red" v-model="volume" hide-details density="compact"
|
|
340
|
+
min="0" max="100" step="5" @update:modelValue="changeVolume">
|
|
341
|
+
</v-slider>
|
|
290
342
|
</v-card-actions>
|
|
291
|
-
<v-progress-linear v-if="
|
|
343
|
+
<v-progress-linear v-if="playingTrack" v-model="positionLength" color="blue" height="25"><strong>{{positionText}}</strong></v-progress-linear>
|
|
292
344
|
</v-card>
|
|
293
345
|
<v-card :height="listHeight" class="overflow-y-auto bg-media">
|
|
294
346
|
<v-list two-line class="bg-media">
|