@christianriedl/media 1.0.2 → 1.0.3

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.
@@ -26,6 +26,11 @@ export interface IPlayerRequest {
26
26
  trackNo?: number;
27
27
  withStreamTitle?: boolean;
28
28
  }
29
+ export interface IPlayerCommand {
30
+ playerName: string;
31
+ cmd: string;
32
+ value: string;
33
+ }
29
34
  export declare class PlayerService {
30
35
  rest: IRest;
31
36
  mediaUrl: string;
@@ -36,6 +41,9 @@ export declare class PlayerService {
36
41
  getPlayers(): Promise<string[]>;
37
42
  getPlayerState(playerName: string): Promise<IPlayerState | null>;
38
43
  play(playerRequest: IPlayerRequest): Promise<boolean>;
39
- playStop(playerName: string): Promise<boolean>;
40
- playPause(playerName: string): Promise<boolean>;
44
+ stop(playerName: string): Promise<boolean>;
45
+ pause(playerName: string): Promise<boolean>;
46
+ next(playerName: string): Promise<boolean>;
47
+ previous(playerName: string): Promise<boolean>;
48
+ command(playerCommand: IPlayerCommand): Promise<boolean>;
41
49
  }
@@ -37,12 +37,24 @@ export class PlayerService {
37
37
  const result = await this.rest.postData('apiplayer/play', playerRequest);
38
38
  return result.ok;
39
39
  }
40
- async playStop(playerName) {
41
- const result = await this.rest.postData('apiplayer/playstop', { playerName: playerName });
40
+ async stop(playerName) {
41
+ const result = await this.rest.postData('apiplayer/playstop/' + playerName);
42
42
  return result.ok;
43
43
  }
44
- async playPause(playerName) {
45
- const result = await this.rest.postData('apiplayer/playpause', { playerName: playerName });
44
+ async pause(playerName) {
45
+ const result = await this.rest.postData('apiplayer/playpause/' + playerName);
46
+ return result.ok;
47
+ }
48
+ async next(playerName) {
49
+ const result = await this.rest.postData('apiplayer/playnext/' + playerName);
50
+ return result.ok;
51
+ }
52
+ async previous(playerName) {
53
+ const result = await this.rest.postData('apiplayer/playprevious/' + playerName);
54
+ return result.ok;
55
+ }
56
+ async command(playerCommand) {
57
+ const result = await this.rest.postData('apiplayer/playcommand', playerCommand);
46
58
  return result.ok;
47
59
  }
48
60
  }
@@ -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;AAqBD,MAAM,OAAO,aAAa;IACtB,IAAI,CAAQ;IACZ,QAAQ,CAAS;IACjB,GAAG,CAAU;IACb,WAAW,GAAa,EAAE,CAAC;IAC3B,YAAY,GAA6B,EAAE,CAAA;IAE3C,YAAY,IAAW,EAAE,GAAY;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IACD,KAAK,CAAC,UAAU;QACZ,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAW,mBAAmB,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,MAAkB,CAAC;QAC9C,OAAO,IAAI,CAAC,WAAW,CAAC;IAC5B,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,UAAkB;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAe,qBAAqB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAC,CAAC,CAAC;QACvG,IAAI,MAAM,CAAC,EAAE,EAAE;YACX,MAAM,WAAW,GAAG,MAAM,CAAC,MAAsB,CAAC;YAClD,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC;YAC5C,OAAO,WAAW,CAAC;SACtB;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,aAA6B;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAiB,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACzF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,QAAQ,CAAC,UAAkB;QAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,oBAAoB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/F,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,UAAkB;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,qBAAqB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAChG,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;CACJ"}
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;AA2BD,MAAM,OAAO,aAAa;IACtB,IAAI,CAAQ;IACZ,QAAQ,CAAS;IACjB,GAAG,CAAU;IACb,WAAW,GAAa,EAAE,CAAC;IAC3B,YAAY,GAA6B,EAAE,CAAA;IAE3C,YAAY,IAAW,EAAE,GAAY;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IACD,KAAK,CAAC,UAAU;QACZ,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAW,mBAAmB,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,MAAkB,CAAC;QAC9C,OAAO,IAAI,CAAC,WAAW,CAAC;IAC5B,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,UAAkB;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAe,qBAAqB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAC,CAAC,CAAC;QACvG,IAAI,MAAM,CAAC,EAAE,EAAE;YACX,MAAM,WAAW,GAAG,MAAM,CAAC,MAAsB,CAAC;YAClD,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC;YAC5C,OAAO,WAAW,CAAC;SACtB;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,aAA6B;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAiB,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACzF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAkB;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,qBAAqB,GAAG,UAAU,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,UAAkB;QAC1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,sBAAsB,GAAG,UAAU,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAkB;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,qBAAqB,GAAG,UAAU,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,QAAQ,CAAC,UAAkB;QAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,yBAAyB,GAAG,UAAU,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,aAA6B;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAM,uBAAuB,EAAE,aAAa,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC,EAAE,CAAC;IACrB,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@christianriedl/media",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "RIC media interfaces",
5
5
 
6
6
  "main": "dist/index.js",
@@ -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 timer = 0;
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) {
@@ -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
- position.value = audio.value!.currentTime;
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 (timer) {
125
- window.clearTimeout(timer);
126
- timer = 0;
131
+ if (syncTimer) {
132
+ window.clearTimeout(syncTimer);
133
+ syncTimer = 0;
127
134
  }
128
- if (currentPlayer != 'Local') {
129
- timer = window.setTimeout(getPlayerState, 1000);
135
+ if (!isLocal.value) {
136
+ syncTimer = window.setTimeout(() => getPlayerState(), 1000);
137
+ syncRemote = true;
130
138
  }
131
139
  }
132
140
  async function getPlayerState() {
133
- const playerState = await playerService.getPlayerState(currentPlayer);
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
- volume.value = playerState.volume;
137
- mute.value = playerState.mute;
138
- if (!selected.value || playerState.folderId != selected.value.DLNAID) {
139
- const album = mediaService.folders[playerState.folderId];
140
- if (album) {
141
- const audios = mediaService.getAudios(selected.Value);
142
- selected.value = audios;
143
- items.splice(0, items.length, ...audios.Files);
144
- playItems.splice(0, items.length, ...audios.Files);
145
- if (playerState.mediaId) {
146
- playIndex.value = items.findIndex((it) => it.DLNAID == playerState.mediaId);
147
- if (playIndex.value >= 0) {
148
- playingTrack.value = items[playIndex.value];
149
- position.value = playingTrack.value.duration * playerState.duration / 100;
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.folderId != 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
+ if (playerState.mediaId) {
158
+ playIndex.value = items.findIndex((it) => it.DLNAID == playerState.mediaId);
159
+ if (playIndex.value >= 0)
160
+ playingTrack.value = items[playIndex.value];
150
161
  }
162
+ computeListHeight();
151
163
  }
152
- computeListHeight();
153
164
  }
154
165
  }
155
- timer = window.setTimeout(getPlayerState, 1000);
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
- playerService.pause(currentPlayer);
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 (playIndex.value > 0)
206
- play(playIndex.value - 1);
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 (playIndex.value < playItems.length - 1)
210
- play(playIndex.value + 1);
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="4">
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="40" :src="selected.ThumbnailUrl">
295
+ <img width="60" :src="selected.ThumbnailUrl">
259
296
  </v-list-item-avatar>
260
297
  </v-col>
261
- <v-col cols="6">
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 small v-if="playingTrackUrl" @click="playpause">
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="playingTrackUrl" @click="previous">
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="playingTrackUrl" @click="next">
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="playingTrackUrl" v-model="positionLength" color="blue" height="25"><strong>{{positionText}}</strong></v-progress-linear>
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">